From f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Tue, 24 Sep 2019 11:56:38 -0400 Subject: deps: update V8 to 7.8.279.9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/29694 Reviewed-By: Colin Ihrig Reviewed-By: Anna Henningsen Reviewed-By: Gus Caplan Reviewed-By: Jiawen Geng Reviewed-By: Michaël Zasso Reviewed-By: Tobias Nießen Reviewed-By: Ujjwal Sharma --- deps/v8/tools/BUILD.gn | 1 + deps/v8/tools/OWNERS | 2 +- deps/v8/tools/clusterfuzz/BUILD.gn | 1 + deps/v8/tools/clusterfuzz/OWNERS | 2 +- .../tools/clusterfuzz/testdata/failure_output.txt | 4 +- .../clusterfuzz/testdata/sanity_check_output.txt | 4 +- deps/v8/tools/clusterfuzz/v8_foozzie.py | 2 +- deps/v8/tools/clusterfuzz/v8_suppressions.py | 1 + deps/v8/tools/debug_helper/BUILD.gn | 104 ++++ deps/v8/tools/debug_helper/DEPS | 3 + deps/v8/tools/debug_helper/README.md | 6 + .../v8/tools/debug_helper/debug-helper-internal.cc | 58 ++ deps/v8/tools/debug_helper/debug-helper-internal.h | 130 ++++ deps/v8/tools/debug_helper/debug-helper.h | 177 ++++++ deps/v8/tools/debug_helper/gen-heap-constants.py | 63 ++ .../v8/tools/debug_helper/get-object-properties.cc | 535 +++++++++++++++++ deps/v8/tools/debug_helper/heap-constants.cc | 51 ++ deps/v8/tools/debug_helper/heap-constants.h | 28 + deps/v8/tools/gcmole/BUILD.gn | 4 + deps/v8/tools/gcmole/GCMOLE.gn | 6 + deps/v8/tools/gcmole/README | 6 + deps/v8/tools/gcmole/gcmole-test.cc | 69 ++- deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 | 2 +- deps/v8/tools/gcmole/gcmole.cc | 91 ++- deps/v8/tools/gcmole/gcmole.lua | 69 ++- deps/v8/tools/gcmole/suspects.whitelist | 4 + deps/v8/tools/gcmole/test-expectations.txt | 20 + deps/v8/tools/gen-postmortem-metadata.py | 2 +- deps/v8/tools/heap-stats/categories.js | 2 +- deps/v8/tools/heap-stats/global-timeline.js | 18 +- deps/v8/tools/heap-stats/trace-file-reader.js | 17 +- deps/v8/tools/run-wasm-api-tests.py | 3 +- deps/v8/tools/testrunner/OWNERS | 2 +- deps/v8/tools/testrunner/base_runner.py | 6 - deps/v8/tools/testrunner/local/junit_output.py | 49 -- deps/v8/tools/testrunner/local/pool.py | 13 +- deps/v8/tools/testrunner/local/variants.py | 2 +- deps/v8/tools/testrunner/testproc/base.py | 14 +- deps/v8/tools/testrunner/testproc/execution.py | 2 +- deps/v8/tools/testrunner/testproc/progress.py | 44 +- deps/v8/tools/testrunner/testproc/timeout.py | 8 +- deps/v8/tools/torque/format-torque.py | 27 +- deps/v8/tools/turbolizer/info-view.html | 2 +- deps/v8/tools/turbolizer/package-lock.json | 47 +- deps/v8/tools/turbolizer/src/disassembly-view.ts | 58 +- deps/v8/tools/turbolizer/src/sequence-view.ts | 2 + deps/v8/tools/turbolizer/src/source-resolver.ts | 119 +++- deps/v8/tools/turbolizer/src/text-view.ts | 14 +- deps/v8/tools/turbolizer/turbo-visualizer.css | 58 ++ deps/v8/tools/v8heapconst.py | 654 ++++++++++----------- deps/v8/tools/wasm/update-wasm-spec-tests.sh | 46 +- deps/v8/tools/whitespace.txt | 4 +- deps/v8/tools/windbg.js | 448 ++++++++++++-- 53 files changed, 2486 insertions(+), 618 deletions(-) create mode 100644 deps/v8/tools/debug_helper/BUILD.gn create mode 100644 deps/v8/tools/debug_helper/DEPS create mode 100644 deps/v8/tools/debug_helper/README.md create mode 100644 deps/v8/tools/debug_helper/debug-helper-internal.cc create mode 100644 deps/v8/tools/debug_helper/debug-helper-internal.h create mode 100644 deps/v8/tools/debug_helper/debug-helper.h create mode 100644 deps/v8/tools/debug_helper/gen-heap-constants.py create mode 100644 deps/v8/tools/debug_helper/get-object-properties.cc create mode 100644 deps/v8/tools/debug_helper/heap-constants.cc create mode 100644 deps/v8/tools/debug_helper/heap-constants.h create mode 100644 deps/v8/tools/gcmole/GCMOLE.gn create mode 100644 deps/v8/tools/gcmole/suspects.whitelist create mode 100644 deps/v8/tools/gcmole/test-expectations.txt delete mode 100644 deps/v8/tools/testrunner/local/junit_output.py (limited to 'deps/v8/tools') diff --git a/deps/v8/tools/BUILD.gn b/deps/v8/tools/BUILD.gn index e6fd743715..8d18f4df75 100644 --- a/deps/v8/tools/BUILD.gn +++ b/deps/v8/tools/BUILD.gn @@ -10,6 +10,7 @@ group("gn_all") { data_deps = [ ":v8_check_static_initializers", + "debug_helper:v8_debug_helper", "gcmole:v8_run_gcmole", "jsfunfuzz:v8_jsfunfuzz", ] diff --git a/deps/v8/tools/OWNERS b/deps/v8/tools/OWNERS index bd9cea5b3e..89ee345b00 100644 --- a/deps/v8/tools/OWNERS +++ b/deps/v8/tools/OWNERS @@ -1,2 +1,2 @@ -file://COMMON_OWNERS +file:../COMMON_OWNERS diff --git a/deps/v8/tools/clusterfuzz/BUILD.gn b/deps/v8/tools/clusterfuzz/BUILD.gn index 88219600a2..e0c4531555 100644 --- a/deps/v8/tools/clusterfuzz/BUILD.gn +++ b/deps/v8/tools/clusterfuzz/BUILD.gn @@ -13,6 +13,7 @@ if (v8_correctness_fuzzer) { "v8_fuzz_config.py", "v8_mock.js", "v8_mock_archs.js", + "v8_sanity_checks.js", "v8_suppressions.js", "v8_suppressions.py", ] diff --git a/deps/v8/tools/clusterfuzz/OWNERS b/deps/v8/tools/clusterfuzz/OWNERS index bdb1d555a4..09e0096a2e 100644 --- a/deps/v8/tools/clusterfuzz/OWNERS +++ b/deps/v8/tools/clusterfuzz/OWNERS @@ -1 +1 @@ -file://INFRA_OWNERS +file:../../INFRA_OWNERS diff --git a/deps/v8/tools/clusterfuzz/testdata/failure_output.txt b/deps/v8/tools/clusterfuzz/testdata/failure_output.txt index fe94bb9ecc..de3c15eab2 100644 --- a/deps/v8/tools/clusterfuzz/testdata/failure_output.txt +++ b/deps/v8/tools/clusterfuzz/testdata/failure_output.txt @@ -9,9 +9,9 @@ # Compared x64,ignition with x64,ignition_turbo # # Flags of x64,ignition: ---correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --turbo-filter=~ --noopt --liftoff --no-wasm-tier-up --flag1 --flag2=0 +--correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --wasm-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --turbo-filter=~ --noopt --liftoff --no-wasm-tier-up --flag1 --flag2=0 # Flags of x64,ignition_turbo: ---correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --flag3 +--correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --wasm-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --flag3 # # Difference: - unknown diff --git a/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt b/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt index 636f4c9d9e..1443c61f2b 100644 --- a/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt +++ b/deps/v8/tools/clusterfuzz/testdata/sanity_check_output.txt @@ -9,9 +9,9 @@ # Compared x64,ignition with x64,ignition_turbo # # Flags of x64,ignition: ---correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --turbo-filter=~ --noopt --liftoff --no-wasm-tier-up +--correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --wasm-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 --turbo-filter=~ --noopt --liftoff --no-wasm-tier-up # Flags of x64,ignition_turbo: ---correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 +--correctness-fuzzer-suppressions --expose-gc --allow-natives-syntax --invoke-weak-callbacks --omit-quit --es-staging --wasm-staging --no-wasm-async-compilation --suppress-asm-messages --random-seed 12345 # # Difference: - unknown diff --git a/deps/v8/tools/clusterfuzz/v8_foozzie.py b/deps/v8/tools/clusterfuzz/v8_foozzie.py index 55f76e8bc6..ff481e9370 100755 --- a/deps/v8/tools/clusterfuzz/v8_foozzie.py +++ b/deps/v8/tools/clusterfuzz/v8_foozzie.py @@ -105,7 +105,7 @@ SANITY_CHECKS = os.path.join(BASE_PATH, 'v8_sanity_checks.js') FLAGS = ['--correctness-fuzzer-suppressions', '--expose-gc', '--allow-natives-syntax', '--invoke-weak-callbacks', '--omit-quit', - '--es-staging', '--no-wasm-async-compilation', + '--es-staging', '--wasm-staging', '--no-wasm-async-compilation', '--suppress-asm-messages'] SUPPORTED_ARCHS = ['ia32', 'x64', 'arm', 'arm64'] diff --git a/deps/v8/tools/clusterfuzz/v8_suppressions.py b/deps/v8/tools/clusterfuzz/v8_suppressions.py index 04f67b2cf9..f1aaa6448a 100644 --- a/deps/v8/tools/clusterfuzz/v8_suppressions.py +++ b/deps/v8/tools/clusterfuzz/v8_suppressions.py @@ -101,6 +101,7 @@ ALLOWED_LINE_DIFFS = [ r'^(.*)TypeError: .* is not a function$', r'^(.*)TypeError: .* is not a constructor$', r'^(.*)TypeError: (.*) is not .*$', + r'^(.*):\d+: TypeError: Message suppressed for fuzzers.*$', r'^(.*)ReferenceError: .* is not defined$', r'^(.*):\d+: ReferenceError: .* is not defined$', 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(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(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> TqObject::GetProperties( + d::MemoryAccessor accessor) const { + return std::vector>(); +} + +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 +#include + +#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 +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> 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> properties_; + + ObjectPropertiesResultExtended public_view_; + std::vector 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> 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 +#include + +#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; + +// 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 +#include + +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 + +#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( \ + 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 object) + : type_check_result(type_check_result), object(std::move(object)) {} + d::TypeCheckResult type_check_result; + std::unique_ptr 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(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(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(address)}; \ + } + STRING_CLASS_TYPES(DEFINE_METHOD) +#undef DEFINE_METHOD + static inline TypedObject HandleInvalidString(uintptr_t address) { + return {d::TypeCheckResult::kUnknownInstanceType, + v8::base::make_unique(address)}; + } + }; + + return i::StringShape(type) + .DispatchToSpecificTypeWithoutCast( + address); +} + +TypedObject GetTypedHeapObject(uintptr_t address, d::MemoryAccessor accessor, + const char* type_hint) { + auto heap_object = v8::base::make_unique(address); + Value 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 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(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(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 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 + void ReadSeqString(const T* object) { + int32_t length = GetOrFinish(object->GetLengthValue(accessor_)); + for (; index_ < length && index_ < limit_ && !done_; ++index_) { + char16_t c = static_cast( + 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(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 + T GetOrFinish(Value 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 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( + typed.type_check_result, brief, typed.object->GetName(), + typed.object->GetProperties(accessor)); +} + +std::unique_ptr 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( + d::TypeCheckResult::kUnableToDecompress, brief, + "v8::internal::TaggedValue", + std::vector>()); + } + + // 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 GetObjectPropertiesImpl( + uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots, + const char* type_hint) { + std::vector> props; + if (static_cast(address) == i::kClearedWeakHeapObjectLower32) { + return v8::base::make_unique( + 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 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( + 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 ptr( + static_cast(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 +#include + +#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 diff --git a/deps/v8/tools/gcmole/BUILD.gn b/deps/v8/tools/gcmole/BUILD.gn index 0434a64ff5..51b9ef527f 100644 --- a/deps/v8/tools/gcmole/BUILD.gn +++ b/deps/v8/tools/gcmole/BUILD.gn @@ -9,12 +9,16 @@ group("v8_run_gcmole") { data = [ "gccause.lua", + "GCMOLE.gn", "gcmole.lua", "gcmole-tools/", "parallel.py", "run-gcmole.py", + "suspects.whitelist", + "test-expectations.txt", # The following contains all relevant source and build files. + "../debug_helper/debug-helper.h", "../../BUILD.gn", "../../base/", "../../include/", diff --git a/deps/v8/tools/gcmole/GCMOLE.gn b/deps/v8/tools/gcmole/GCMOLE.gn new file mode 100644 index 0000000000..62da0a084b --- /dev/null +++ b/deps/v8/tools/gcmole/GCMOLE.gn @@ -0,0 +1,6 @@ +action("gcmole") { + sources = [ + ### gcmole(all) ### + "tools/gcmole/gcmole-test.cc", + ] +} diff --git a/deps/v8/tools/gcmole/README b/deps/v8/tools/gcmole/README index 578ea56219..48785b871a 100644 --- a/deps/v8/tools/gcmole/README +++ b/deps/v8/tools/gcmole/README @@ -71,6 +71,12 @@ can be ignored. If any errors were found driver exits with non-zero status. +TESTING ----------------------------------------------------------------------- + +Tests are automatically run by the main lua runner. Expectations are in +test-expectations.txt and need to be updated whenever the sources of the tests +in gcmole-test.cc are modified (line numbers also count). + PACKAGING --------------------------------------------------------------------- gcmole is deployed on V8's buildbot infrastructure to run it as part of the diff --git a/deps/v8/tools/gcmole/gcmole-test.cc b/deps/v8/tools/gcmole/gcmole-test.cc index c00c6e5539..3af1bac3b5 100644 --- a/deps/v8/tools/gcmole/gcmole-test.cc +++ b/deps/v8/tools/gcmole/gcmole-test.cc @@ -5,26 +5,43 @@ #include "src/execution/isolate.h" #include "src/handles/handles-inl.h" #include "src/handles/handles.h" +#include "src/objects/foreign-inl.h" +#include "src/objects/managed.h" #include "src/objects/maybe-object.h" #include "src/objects/object-macros.h" namespace v8 { namespace internal { +// ------- Test simple argument evaluation order problems --------- + Handle CauseGC(Handle obj, Isolate* isolate) { isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting); return obj; } +Object CauseGCRaw(Object obj, Isolate* isolate) { + isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting); + + return obj; +} + +Managed CauseGCManaged(int i, Isolate* isolate) { + isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting); + + return Managed::cast(Smi::FromInt(i)); +} + void TwoArgumentsFunction(Object a, Object b) { - a->Print(); - b->Print(); + a.Print(); + b.Print(); } void TestTwoArguments(Isolate* isolate) { Handle obj1 = isolate->factory()->NewJSObjectWithNullProto(); Handle obj2 = isolate->factory()->NewJSObjectWithNullProto(); + // Should cause warning. TwoArgumentsFunction(*CauseGC(obj1, isolate), *CauseGC(obj2, isolate)); } @@ -36,13 +53,16 @@ void TwoSizeTArgumentsFunction(size_t a, size_t b) { void TestTwoSizeTArguments(Isolate* isolate) { Handle obj1 = isolate->factory()->NewJSObjectWithNullProto(); Handle obj2 = isolate->factory()->NewJSObjectWithNullProto(); + // Should cause warning. TwoSizeTArgumentsFunction(sizeof(*CauseGC(obj1, isolate)), sizeof(*CauseGC(obj2, isolate))); } +// --------- Test problems with method arguments ---------- + class SomeObject : public Object { public: - void Method(Object a) { a->Print(); } + void Method(Object a) { a.Print(); } SomeObject& operator=(const Object& b) { this->Print(); @@ -58,14 +78,57 @@ void TestMethodCall(Isolate* isolate) { SomeObject obj; Handle so = handle(obj, isolate); Handle obj1 = isolate->factory()->NewJSObjectWithNullProto(); + // Should cause warning. so->Method(*CauseGC(obj1, isolate)); + // Should cause warning. + so->Method(CauseGCRaw(*obj1, isolate)); } void TestOperatorCall(Isolate* isolate) { SomeObject obj; Handle obj1 = isolate->factory()->NewJSObjectWithNullProto(); + // Should not cause warning. obj = *CauseGC(obj1, isolate); } +// --------- Test for templated sub-classes of Object ---------- + +void TestFollowingTemplates(Isolate* isolate) { + // Should cause warning. + CauseGCManaged(42, isolate); +} + +// --------- Test for correctly resolving virtual methods ---------- + +class BaseObject { + public: + virtual Handle VirtualCauseGC(Handle obj, Isolate* isolate) { + return obj; + } +}; + +class DerivedObject : public BaseObject { + public: + Handle VirtualCauseGC(Handle obj, Isolate* isolate) override { + isolate->heap()->CollectGarbage(OLD_SPACE, + GarbageCollectionReason::kTesting); + + return obj; + } +}; + +void TestFollowingVirtualFunctions(Isolate* isolate) { + DerivedObject derived; + BaseObject* base = &derived; + Handle obj1 = isolate->factory()->NewJSObjectWithNullProto(); + + SomeObject so; + Handle so_handle = handle(so, isolate); + // Should cause warning. + so_handle->Method(*derived.VirtualCauseGC(obj1, isolate)); + // Should cause warning. + so_handle->Method(*base->VirtualCauseGC(obj1, isolate)); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 b/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 index 718e967e3b..8f7876fa51 100644 --- a/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 +++ b/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 @@ -1 +1 @@ -3d4ba1759c3d5bc7e98c466d24fa0c43f186ba79 \ No newline at end of file +d2f949820bf1ee7343a7b5f46987a3657aaea2e9 \ No newline at end of file diff --git a/deps/v8/tools/gcmole/gcmole.cc b/deps/v8/tools/gcmole/gcmole.cc index 6631583478..806100d381 100644 --- a/deps/v8/tools/gcmole/gcmole.cc +++ b/deps/v8/tools/gcmole/gcmole.cc @@ -47,6 +47,7 @@ namespace { typedef std::string MangledName; typedef std::set CalleesSet; +typedef std::map CalleesMap; static bool GetMangledName(clang::MangleContext* ctx, const clang::NamedDecl* decl, @@ -138,14 +139,16 @@ class CalleesPrinter : public clang::RecursiveASTVisitor { virtual bool VisitDeclRefExpr(clang::DeclRefExpr* expr) { // If function mentions EXTERNAL VMState add artificial garbage collection // mark. - if (IsExternalVMState(expr->getDecl())) AddCallee("CollectGarbage"); + if (IsExternalVMState(expr->getDecl())) + AddCallee("CollectGarbage", "CollectGarbage"); return true; } void AnalyzeFunction(const clang::FunctionDecl* f) { MangledName name; if (InV8Namespace(f) && GetMangledName(ctx_, f, &name)) { - AddCallee(name); + const std::string& function = f->getNameAsString(); + AddCallee(name, function); const clang::FunctionDecl* body = NULL; if (f->hasBody(body) && !Analyzed(name)) { @@ -176,21 +179,22 @@ class CalleesPrinter : public clang::RecursiveASTVisitor { scopes_.pop(); } - void AddCallee(const MangledName& name) { + void AddCallee(const MangledName& name, const MangledName& function) { if (!scopes_.empty()) scopes_.top()->insert(name); + mangled_to_function_[name] = function; } void PrintCallGraph() { for (Callgraph::const_iterator i = callgraph_.begin(), e = callgraph_.end(); i != e; ++i) { - std::cout << i->first << "\n"; + std::cout << i->first << "," << mangled_to_function_[i->first] << "\n"; CalleesSet* callees = i->second; for (CalleesSet::const_iterator j = callees->begin(), e = callees->end(); j != e; ++j) { - std::cout << "\t" << *j << "\n"; + std::cout << "\t" << *j << "," << mangled_to_function_[*j] << "\n"; } } } @@ -200,6 +204,7 @@ class CalleesPrinter : public clang::RecursiveASTVisitor { std::stack scopes_; Callgraph callgraph_; + CalleesMap mangled_to_function_; }; @@ -234,23 +239,40 @@ class FunctionDeclarationFinder CalleesPrinter* callees_printer_; }; - -static bool loaded = false; +static bool gc_suspects_loaded = false; static CalleesSet gc_suspects; - +static CalleesSet gc_functions; +static bool whitelist_loaded = false; +static CalleesSet suspects_whitelist; static void LoadGCSuspects() { - if (loaded) return; + if (gc_suspects_loaded) return; std::ifstream fin("gcsuspects"); - std::string s; + std::string mangled, function; - while (fin >> s) gc_suspects.insert(s); + while (!fin.eof()) { + std::getline(fin, mangled, ','); + gc_suspects.insert(mangled); + std::getline(fin, function); + gc_functions.insert(function); + } - loaded = true; + gc_suspects_loaded = true; } +static void LoadSuspectsWhitelist() { + if (whitelist_loaded) return; + + std::ifstream fin("tools/gcmole/suspects.whitelist"); + std::string s; + + while (fin >> s) suspects_whitelist.insert(s); + whitelist_loaded = true; +} + +// Looks for exact match of the mangled name static bool KnownToCauseGC(clang::MangleContext* ctx, const clang::FunctionDecl* decl) { LoadGCSuspects(); @@ -265,6 +287,25 @@ static bool KnownToCauseGC(clang::MangleContext* ctx, return false; } +// Looks for partial match of only the function name +static bool SuspectedToCauseGC(clang::MangleContext* ctx, + const clang::FunctionDecl* decl) { + LoadGCSuspects(); + + if (!InV8Namespace(decl)) return false; + + LoadSuspectsWhitelist(); + if (suspects_whitelist.find(decl->getNameAsString()) != + suspects_whitelist.end()) { + return false; + } + + if (gc_functions.find(decl->getNameAsString()) != gc_functions.end()) { + return true; + } + + return false; +} static const int kNoEffect = 0; static const int kCausesGC = 1; @@ -910,8 +951,30 @@ class FunctionAnalyzer { RepresentsRawPointerType(call->getType())); clang::FunctionDecl* callee = call->getDirectCallee(); - if ((callee != NULL) && KnownToCauseGC(ctx_, callee)) { - out.setGC(); + if (callee != NULL) { + if (KnownToCauseGC(ctx_, callee)) { + out.setGC(); + } + + clang::CXXMethodDecl* method = + llvm::dyn_cast_or_null(callee); + if (method != NULL && method->isVirtual()) { + clang::CXXMemberCallExpr* memcall = + llvm::dyn_cast_or_null(call); + if (memcall != NULL) { + clang::CXXMethodDecl* target = method->getDevirtualizedMethod( + memcall->getImplicitObjectArgument(), false); + if (target != NULL) { + if (KnownToCauseGC(ctx_, target)) { + out.setGC(); + } + } else { + if (SuspectedToCauseGC(ctx_, method)) { + out.setGC(); + } + } + } + } } return out; diff --git a/deps/v8/tools/gcmole/gcmole.lua b/deps/v8/tools/gcmole/gcmole.lua index ae17fdc5f6..6758973457 100644 --- a/deps/v8/tools/gcmole/gcmole.lua +++ b/deps/v8/tools/gcmole/gcmole.lua @@ -183,12 +183,19 @@ end ------------------------------------------------------------------------------- -local function ParseGNFile() +local function ParseGNFile(for_test) local result = {} - local gn_files = { - { "BUILD.gn", '"([^"]-%.cc)"', "" }, - { "test/cctest/BUILD.gn", '"(test-[^"]-%.cc)"', "test/cctest/" } - } + local gn_files + if for_test then + gn_files = { + { "tools/gcmole/GCMOLE.gn", '"([^"]-%.cc)"', "" } + } + else + gn_files = { + { "BUILD.gn", '"([^"]-%.cc)"', "" }, + { "test/cctest/BUILD.gn", '"(test-[^"]-%.cc)"', "test/cctest/" } + } + end for i = 1, #gn_files do local filename = gn_files[i][1] @@ -231,7 +238,8 @@ local function BuildFileList(sources, props) end -local gn_sources = ParseGNFile() +local gn_sources = ParseGNFile(false) +local gn_test_sources = ParseGNFile(true) local function FilesForArch(arch) return BuildFileList(gn_sources, { os = 'linux', @@ -240,6 +248,13 @@ local function FilesForArch(arch) simulator = ''}) end +local function FilesForTest(arch) + return BuildFileList(gn_test_sources, { os = 'linux', + arch = arch, + mode = 'debug', + simulator = ''}) +end + local mtConfig = {} mtConfig.__index = mtConfig @@ -393,8 +408,13 @@ end -------------------------------------------------------------------------------- -- Analysis -local function CheckCorrectnessForArch(arch) - local files = FilesForArch(arch) +local function CheckCorrectnessForArch(arch, for_test) + local files + if for_test then + files = FilesForTest(arch) + else + files = FilesForArch(arch) + end local cfg = ARCHITECTURES[arch] if not FLAGS.reuse_gcsuspects then @@ -403,6 +423,7 @@ local function CheckCorrectnessForArch(arch) local processed_files = 0 local errors_found = false + local output = "" local function SearchForErrors(filename, lines) processed_files = processed_files + 1 for l in lines do @@ -410,7 +431,11 @@ local function CheckCorrectnessForArch(arch) l:match "^[^:]+:%d+:%d+:" or l:match "error" or l:match "warning" - print(l) + if for_test then + output = output.."\n"..l + else + print(l) + end end end @@ -427,18 +452,34 @@ local function CheckCorrectnessForArch(arch) processed_files, errors_found and "Errors found" or "No errors found") - return errors_found + return errors_found, output end -local function SafeCheckCorrectnessForArch(arch) - local status, errors = pcall(CheckCorrectnessForArch, arch) +local function SafeCheckCorrectnessForArch(arch, for_test) + local status, errors, output = pcall(CheckCorrectnessForArch, arch, for_test) if not status then print(string.format("There was an error: %s", errors)) errors = true end - return errors + return errors, output +end + +local function TestRun() + local errors, output = SafeCheckCorrectnessForArch('x64', true) + + local filename = "tools/gcmole/test-expectations.txt" + local exp_file = assert(io.open(filename), "failed to open test expectations file") + local expectations = exp_file:read('*all') + + if output ~= expectations then + log("** Output mismatch from running tests. Please run them manually.") + else + log("** Tests ran successfully") + end end +TestRun() + local errors = false for _, arch in ipairs(ARCHS) do @@ -446,7 +487,7 @@ for _, arch in ipairs(ARCHS) do error ("Unknown arch: " .. arch) end - errors = SafeCheckCorrectnessForArch(arch, report) or errors + errors = SafeCheckCorrectnessForArch(arch, false) or errors end os.exit(errors and 1 or 0) diff --git a/deps/v8/tools/gcmole/suspects.whitelist b/deps/v8/tools/gcmole/suspects.whitelist new file mode 100644 index 0000000000..01db7401f2 --- /dev/null +++ b/deps/v8/tools/gcmole/suspects.whitelist @@ -0,0 +1,4 @@ +IsConstructor +IsEval +IsAsync +IsPromiseAll diff --git a/deps/v8/tools/gcmole/test-expectations.txt b/deps/v8/tools/gcmole/test-expectations.txt new file mode 100644 index 0000000000..36a026a12e --- /dev/null +++ b/deps/v8/tools/gcmole/test-expectations.txt @@ -0,0 +1,20 @@ + +tools/gcmole/gcmole-test.cc:45:3: warning: Possible problem with evaluation order. + TwoArgumentsFunction(*CauseGC(obj1, isolate), *CauseGC(obj2, isolate)); + ^ +tools/gcmole/gcmole-test.cc:57:3: warning: Possible problem with evaluation order. + TwoSizeTArgumentsFunction(sizeof(*CauseGC(obj1, isolate)), + ^ +tools/gcmole/gcmole-test.cc:82:7: warning: Possible problem with evaluation order. + so->Method(*CauseGC(obj1, isolate)); + ^ +tools/gcmole/gcmole-test.cc:84:7: warning: Possible problem with evaluation order. + so->Method(CauseGCRaw(*obj1, isolate)); + ^ +tools/gcmole/gcmole-test.cc:128:14: warning: Possible problem with evaluation order. + so_handle->Method(*derived.VirtualCauseGC(obj1, isolate)); + ^ +tools/gcmole/gcmole-test.cc:130:14: warning: Possible problem with evaluation order. + so_handle->Method(*base->VirtualCauseGC(obj1, isolate)); + ^ +6 warnings generated. diff --git a/deps/v8/tools/gen-postmortem-metadata.py b/deps/v8/tools/gen-postmortem-metadata.py index b5aba23220..0715b07dc1 100644 --- a/deps/v8/tools/gen-postmortem-metadata.py +++ b/deps/v8/tools/gen-postmortem-metadata.py @@ -166,7 +166,7 @@ consts_misc = [ { 'name': 'bit_field3_number_of_own_descriptors_shift', 'value': 'Map::NumberOfOwnDescriptorsBits::kShift' }, { 'name': 'class_Map__instance_descriptors_offset', - 'value': 'Map::kInstanceDescriptorsOffset' }, + 'value': 'Map::kInstanceDescriptorsOffset' }, { 'name': 'off_fp_context_or_frame_type', 'value': 'CommonFrameConstants::kContextOrFrameTypeOffset'}, diff --git a/deps/v8/tools/heap-stats/categories.js b/deps/v8/tools/heap-stats/categories.js index e02571b4f8..6560758f3e 100644 --- a/deps/v8/tools/heap-stats/categories.js +++ b/deps/v8/tools/heap-stats/categories.js @@ -77,7 +77,7 @@ const CATEGORIES = new Map([ 'JS_TO_WASM_FUNCTION', 'JS_TYPED_ARRAY_TYPE', 'JS_WEAK_MAP_TYPE', - 'MUTABLE_HEAP_NUMBER_TYPE', + 'HEAP_NUMBER_TYPE', 'NATIVE_CONTEXT_TYPE', 'OBJECT_PROPERTY_DICTIONARY_TYPE', 'ONE_BYTE_INTERNALIZED_STRING_TYPE', diff --git a/deps/v8/tools/heap-stats/global-timeline.js b/deps/v8/tools/heap-stats/global-timeline.js index 3830b7ca33..c34ba2b913 100644 --- a/deps/v8/tools/heap-stats/global-timeline.js +++ b/deps/v8/tools/heap-stats/global-timeline.js @@ -63,9 +63,12 @@ class GlobalTimeline extends HTMLElement { {type: 'number', label: 'Ptr compression benefit'}, {type: 'string', role: 'tooltip'}, {type: 'number', label: 'Embedder fields'}, - {type: 'number', label: 'Tagged fields'}, + {type: 'number', label: 'Tagged fields (excl. in-object Smis)'}, + {type: 'number', label: 'In-object Smi-only fields'}, {type: 'number', label: 'Other raw fields'}, - {type: 'number', label: 'Unboxed doubles'} + {type: 'number', label: 'Unboxed doubles'}, + {type: 'number', label: 'Boxed doubles'}, + {type: 'number', label: 'String data'} ]; const chart_data = [labels]; const isolate_data = this.data[this.selection.isolate]; @@ -78,10 +81,14 @@ class GlobalTimeline extends HTMLElement { const data = []; data.push(gc_data.time * kMillis2Seconds); const total = data_set.tagged_fields + + data_set.inobject_smi_fields + data_set.embedder_fields + data_set.other_raw_fields + - data_set.unboxed_double_fields; - const ptr_compr_benefit = data_set.tagged_fields / 2; + data_set.unboxed_double_fields + + data_set.boxed_double_fields + + data_set.string_data; + const ptr_compr_benefit = + (data_set.inobject_smi_fields + data_set.tagged_fields) / 2; const ptr_compr_benefit_perc = ptr_compr_benefit / total * 100; sum_total += total; sum_ptr_compr_benefit_perc += ptr_compr_benefit_perc; @@ -93,8 +100,11 @@ class GlobalTimeline extends HTMLElement { data.push(tooltip); data.push(data_set.embedder_fields / KB); data.push(data_set.tagged_fields / KB); + data.push(data_set.inobject_smi_fields / KB); data.push(data_set.other_raw_fields / KB); data.push(data_set.unboxed_double_fields / KB); + data.push(data_set.boxed_double_fields / KB); + data.push(data_set.string_data / KB); chart_data.push(data); }); const avg_ptr_compr_benefit_perc = diff --git a/deps/v8/tools/heap-stats/trace-file-reader.js b/deps/v8/tools/heap-stats/trace-file-reader.js index 4fec9a1cb9..86d9d7d551 100644 --- a/deps/v8/tools/heap-stats/trace-file-reader.js +++ b/deps/v8/tools/heap-stats/trace-file-reader.js @@ -137,11 +137,15 @@ class TraceFileReader extends HTMLElement { } addFieldTypeData(data, isolate, gc_id, data_set, tagged_fields, - embedder_fields, unboxed_double_fields, other_raw_fields) { + inobject_smi_fields, embedder_fields, unboxed_double_fields, + boxed_double_fields, string_data, other_raw_fields) { data[isolate].gcs[gc_id][data_set].field_data = { tagged_fields, + inobject_smi_fields, embedder_fields, unboxed_double_fields, + boxed_double_fields, + string_data, other_raw_fields }; } @@ -217,8 +221,12 @@ class TraceFileReader extends HTMLElement { const field_data = entry.field_data; this.addFieldTypeData(data, isolate, gc_id, data_set, - field_data.tagged_fields, field_data.embedder_fields, + field_data.tagged_fields, + field_data.inobject_smi_fields, + field_data.embedder_fields, field_data.unboxed_double_fields, + field_data.boxed_double_fields, + field_data.string_data, field_data.other_raw_fields); data[isolate].gcs[gc_id][data_set].bucket_sizes = @@ -282,8 +290,9 @@ class TraceFileReader extends HTMLElement { this.createOrUpdateEntryIfNeeded(data, entry); this.createDatasetIfNeeded(data, entry, entry.key); this.addFieldTypeData(data, entry.isolate, entry.id, entry.key, - entry.tagged_fields, entry.embedder_fields, - entry.unboxed_double_fields, entry.other_raw_fields); + entry.tagged_fields, entry.embedder_fields, entry.inobject_smi_fields, + entry.unboxed_double_fields, entry.boxed_double_fields, + entry.string_data, entry.other_raw_fields); } else if (entry.type === 'instance_type_data') { if (entry.id in data[entry.isolate].gcs) { this.createOrUpdateEntryIfNeeded(data, entry); diff --git a/deps/v8/tools/run-wasm-api-tests.py b/deps/v8/tools/run-wasm-api-tests.py index 79f53cb927..ff37c8a465 100755 --- a/deps/v8/tools/run-wasm-api-tests.py +++ b/deps/v8/tools/run-wasm-api-tests.py @@ -38,7 +38,8 @@ CLANG_PATH = os.path.join(CHECKOUT_PATH, "third_party", "llvm-build", "Release+Asserts", "bin") EXAMPLES = ["hello", "callback", "trap", "reflect", "global", "table", - "memory", "finalize", "serialize", "threads"] + "memory", "finalize", "serialize", "threads", "hostref", "multi", + "start"] CLANG = { "name": "Clang", diff --git a/deps/v8/tools/testrunner/OWNERS b/deps/v8/tools/testrunner/OWNERS index bdb1d555a4..09e0096a2e 100644 --- a/deps/v8/tools/testrunner/OWNERS +++ b/deps/v8/tools/testrunner/OWNERS @@ -1 +1 @@ -file://INFRA_OWNERS +file:../../INFRA_OWNERS diff --git a/deps/v8/tools/testrunner/base_runner.py b/deps/v8/tools/testrunner/base_runner.py index 15c5335878..7f9b43435f 100644 --- a/deps/v8/tools/testrunner/base_runner.py +++ b/deps/v8/tools/testrunner/base_runner.py @@ -349,9 +349,6 @@ class BaseTestRunner(object): "color, mono)") parser.add_option("--json-test-results", help="Path to a file for storing json results.") - parser.add_option("--junitout", help="File name of the JUnit output") - parser.add_option("--junittestsuite", default="v8tests", - help="The testsuite name in the JUnit output file") parser.add_option("--exit-after-n-failures", type="int", default=100, help="Exit after the first N failures instead of " "running all tests. Pass 0 to disable this feature.") @@ -794,9 +791,6 @@ class BaseTestRunner(object): def _create_progress_indicators(self, test_count, options): procs = [PROGRESS_INDICATORS[options.progress]()] - if options.junitout: - procs.append(progress.JUnitTestProgressIndicator(options.junitout, - options.junittestsuite)) if options.json_test_results: procs.append(progress.JsonTestProgressIndicator( self.framework_name, diff --git a/deps/v8/tools/testrunner/local/junit_output.py b/deps/v8/tools/testrunner/local/junit_output.py deleted file mode 100644 index 52f31ec422..0000000000 --- a/deps/v8/tools/testrunner/local/junit_output.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2013 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -import xml.etree.ElementTree as xml - - -class JUnitTestOutput: - def __init__(self, test_suite_name): - self.root = xml.Element("testsuite") - self.root.attrib["name"] = test_suite_name - - def HasRunTest(self, test_name, test_cmd, test_duration, test_failure): - testCaseElement = xml.Element("testcase") - testCaseElement.attrib["name"] = test_name - testCaseElement.attrib["cmd"] = test_cmd - testCaseElement.attrib["time"] = str(round(test_duration, 3)) - if len(test_failure): - failureElement = xml.Element("failure") - failureElement.text = test_failure - testCaseElement.append(failureElement) - self.root.append(testCaseElement) - - def FinishAndWrite(self, f): - xml.ElementTree(self.root).write(f, "UTF-8") diff --git a/deps/v8/tools/testrunner/local/pool.py b/deps/v8/tools/testrunner/local/pool.py index e0b0ec41c7..9defdd30ee 100644 --- a/deps/v8/tools/testrunner/local/pool.py +++ b/deps/v8/tools/testrunner/local/pool.py @@ -115,7 +115,15 @@ class Pool(): # Necessary to not overflow the queue's pipe if a keyboard interrupt happens. BUFFER_FACTOR = 4 - def __init__(self, num_workers, heartbeat_timeout=1): + def __init__(self, num_workers, heartbeat_timeout=1, notify_fun=None): + """ + Args: + num_workers: Number of worker processes to run in parallel. + heartbeat_timeout: Timeout in seconds for waiting for results. Each time + the timeout is reached, a heartbeat is signalled and timeout is reset. + notify_fun: Callable called to signale some events like termination. The + event name is passed as string. + """ self.num_workers = num_workers self.processes = [] self.terminated = False @@ -130,6 +138,7 @@ class Pool(): # work_queue. self.processing_count = 0 self.heartbeat_timeout = heartbeat_timeout + self.notify = notify_fun or (lambda x: x) # Disable sigint and sigterm to prevent subprocesses from capturing the # signals. @@ -261,11 +270,13 @@ class Pool(): for p in self.processes: os.kill(p.pid, signal.SIGTERM) + self.notify("Joining workers") for p in self.processes: p.join() # Drain the queues to prevent stderr chatter when queues are garbage # collected. + self.notify("Draining queues") try: while True: self.work_queue.get(False) except: diff --git a/deps/v8/tools/testrunner/local/variants.py b/deps/v8/tools/testrunner/local/variants.py index 4b0cf1553b..fe63d0b935 100644 --- a/deps/v8/tools/testrunner/local/variants.py +++ b/deps/v8/tools/testrunner/local/variants.py @@ -23,7 +23,7 @@ ALL_VARIANT_FLAGS = { "nooptimization": [["--no-opt", "--liftoff", "--no-wasm-tier-up"]], "slow_path": [["--force-slow-path"]], "stress": [["--stress-opt", "--always-opt", "--no-liftoff", - "--no-wasm-tier-up"]], + "--no-wasm-tier-up", '--stress-lazy-source-positions']], "stress_js_bg_compile_wasm_code_gc": [["--stress-background-compile", "--wasm-code-gc", "--stress-wasm-code-gc"]], diff --git a/deps/v8/tools/testrunner/testproc/base.py b/deps/v8/tools/testrunner/testproc/base.py index c52c779752..6048ef5d15 100644 --- a/deps/v8/tools/testrunner/testproc/base.py +++ b/deps/v8/tools/testrunner/testproc/base.py @@ -109,6 +109,19 @@ class TestProc(object): ### Communication + def notify_previous(self, event): + self._on_event(event) + if self._prev_proc: + self._prev_proc.notify_previous(event) + + def _on_event(self, event): + """Called when processors to the right signal events, e.g. termination. + + Args: + event: A text describing the signalled event. + """ + pass + def _send_test(self, test): """Helper method for sending test to the next processor.""" return self._next_proc.next_test(test) @@ -120,7 +133,6 @@ class TestProc(object): self._prev_proc.result_for(test, result) - class TestProcObserver(TestProc): """Processor used for observing the data.""" def __init__(self): diff --git a/deps/v8/tools/testrunner/testproc/execution.py b/deps/v8/tools/testrunner/testproc/execution.py index 68ecf45a37..aaf0db1f8f 100644 --- a/deps/v8/tools/testrunner/testproc/execution.py +++ b/deps/v8/tools/testrunner/testproc/execution.py @@ -45,7 +45,7 @@ class ExecutionProc(base.TestProc): def __init__(self, jobs, outproc_factory=None): super(ExecutionProc, self).__init__() - self._pool = pool.Pool(jobs) + self._pool = pool.Pool(jobs, notify_fun=self.notify_previous) self._outproc_factory = outproc_factory or (lambda t: t.output_proc) self._tests = {} diff --git a/deps/v8/tools/testrunner/testproc/progress.py b/deps/v8/tools/testrunner/testproc/progress.py index 3ba10f9528..8826c36ea4 100644 --- a/deps/v8/tools/testrunner/testproc/progress.py +++ b/deps/v8/tools/testrunner/testproc/progress.py @@ -13,7 +13,6 @@ import sys import time from . import base -from ..local import junit_output # Base dir of the build products for Release and Debug. @@ -150,6 +149,10 @@ class VerboseProgressIndicator(SimpleProgressIndicator): self._print('Still working...') self._print_processes_linux() + def _on_event(self, event): + self._print(event) + self._print_processes_linux() + class DotsProgressIndicator(SimpleProgressIndicator): def __init__(self): @@ -282,45 +285,6 @@ class MonochromeProgressIndicator(CompactProgressIndicator): print(("\r" + (" " * last_length) + "\r"), end='') -class JUnitTestProgressIndicator(ProgressIndicator): - def __init__(self, junitout, junittestsuite): - super(JUnitTestProgressIndicator, self).__init__() - self._requirement = base.DROP_PASS_STDOUT - - self.outputter = junit_output.JUnitTestOutput(junittestsuite) - if junitout: - self.outfile = open(junitout, "w") - else: - self.outfile = sys.stdout - - def _on_result_for(self, test, result): - # TODO(majeski): Support for dummy/grouped results - fail_text = "" - output = result.output - if result.has_unexpected_output: - stdout = output.stdout.strip() - if len(stdout): - fail_text += "stdout:\n%s\n" % stdout - stderr = output.stderr.strip() - if len(stderr): - fail_text += "stderr:\n%s\n" % stderr - fail_text += "Command: %s" % result.cmd.to_string() - if output.HasCrashed(): - fail_text += "exit code: %d\n--- CRASHED ---" % output.exit_code - if output.HasTimedOut(): - fail_text += "--- TIMEOUT ---" - self.outputter.HasRunTest( - test_name=str(test), - test_cmd=result.cmd.to_string(relative=True), - test_duration=output.duration, - test_failure=fail_text) - - def finished(self): - self.outputter.FinishAndWrite(self.outfile) - if self.outfile != sys.stdout: - self.outfile.close() - - class JsonTestProgressIndicator(ProgressIndicator): def __init__(self, framework_name, json_test_results, arch, mode): super(JsonTestProgressIndicator, self).__init__() diff --git a/deps/v8/tools/testrunner/testproc/timeout.py b/deps/v8/tools/testrunner/testproc/timeout.py index 54dc60e9b4..9a4e88c8f0 100644 --- a/deps/v8/tools/testrunner/testproc/timeout.py +++ b/deps/v8/tools/testrunner/testproc/timeout.py @@ -14,15 +14,15 @@ class TimeoutProc(base.TestProcObserver): self._start = time.time() def _on_next_test(self, test): - self._on_event() + self.__on_event() def _on_result_for(self, test, result): - self._on_event() + self.__on_event() def _on_heartbeat(self): - self._on_event() + self.__on_event() - def _on_event(self): + def __on_event(self): if not self.is_stopped: if time.time() - self._start > self._duration_sec: print('>>> Total timeout reached.') diff --git a/deps/v8/tools/torque/format-torque.py b/deps/v8/tools/torque/format-torque.py index 2150d7e0cc..2e04e659c1 100755 --- a/deps/v8/tools/torque/format-torque.py +++ b/deps/v8/tools/torque/format-torque.py @@ -20,18 +20,9 @@ kPercentEscape = r'α'; # Unicode alpha def preprocess(input): input = re.sub(r'(if\s+)constexpr(\s*\()', r'\1/*COxp*/\2', input) input = re.sub(r'(\s+)operator\s*(\'[^\']+\')', r'\1/*_OPE \2*/', input) - - # Mangle typeswitches to look like switch statements with the extra type - # information and syntax encoded in comments. - input = re.sub(r'(\s+)typeswitch\s*\(', r'\1/*_TYPE*/switch (', input) - input = re.sub(r'(\s+)case\s*\(\s*([^\:]+)\s*\)(\s*)\:\s*deferred', - r'\1case \2: /*_TSXDEFERRED_*/', input) - input = re.sub(r'(\s+)case\s*\(\s*([^\:]+)\s*\)(\s*)\:', - r'\1case \2: /*_TSX*/', input) - input = re.sub(r'(\s+)case\s*\(\s*([^\s]+)\s*\:\s*([^\:]+)\s*\)(\s*)\:\s*deferred', - r'\1case \3: /*_TSVDEFERRED_\2:*/', input) - input = re.sub(r'(\s+)case\s*\(\s*([^\s]+)\s*\:\s*([^\:]+)\s*\)(\s*)\:', - r'\1case \3: /*_TSV\2:*/', input) + input = re.sub(r'\btypeswitch\s*(\([^{]*\))\s{', r' if /*tPsW*/ \1 {', input) + input = re.sub(r'\bcase\s*(\([^{]*\))\s*:\s*deferred\s*{', r' if /*cAsEdEfF*/ \1 {', input) + input = re.sub(r'\bcase\s*(\([^{]*\))\s*:\s*{', r' if /*cA*/ \1 {', input) # Add extra space around | operators to fix union types later. while True: @@ -65,15 +56,9 @@ def postprocess(output): output = re.sub(r'(\S+)\s*: type([,>])', r'\1: type\2', output) output = re.sub(r'(\n\s*)labels( [A-Z])', r'\1 labels\2', output) output = re.sub(r'\/\*_OPE \'([^\']+)\'\*\/', r"operator '\1'", output) - output = re.sub(r'\/\*_TYPE\*\/(\s*)switch', r'typeswitch', output) - output = re.sub(r'case (\w+)\:\s*\/\*_TSXDEFERRED_\*\/', - r'case (\1): deferred', output) - output = re.sub(r'case (\w+)\:\s*\/\*_TSX\*\/', - r'case (\1):', output) - output = re.sub(r'case (\w+)\:\s*\/\*_TSVDEFERRED_([^\:]+)\:\*\/', - r'case (\2: \1): deferred', output) - output = re.sub(r'case (\w+)\:\s*\/\*_TSV([^\:]+)\:\*\/', - r'case (\2: \1):', output) + output = re.sub(r'\bif\s*\/\*tPsW\*\/', r'typeswitch', output) + output = re.sub(r'\bif\s*\/\*cA\*\/\s*(\([^{]*\))\s*{', r'case \1: {', output) + output = re.sub(r'\bif\s*\/\*cAsEdEfF\*\/\s*(\([^{]*\))\s*{', r'case \1: deferred {', output) output = re.sub(r'\n_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/', r"\n generates '\1'", output) output = re.sub(r'_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/', diff --git a/deps/v8/tools/turbolizer/info-view.html b/deps/v8/tools/turbolizer/info-view.html index b523e655aa..dc9c177f60 100644 --- a/deps/v8/tools/turbolizer/info-view.html +++ b/deps/v8/tools/turbolizer/info-view.html @@ -107,7 +107,7 @@ ^42: - Select exactly the node with id 14. + Select exactly the node with id 42. Origin: #42  diff --git a/deps/v8/tools/turbolizer/package-lock.json b/deps/v8/tools/turbolizer/package-lock.json index 9c8049fdb5..e30838aa3b 100644 --- a/deps/v8/tools/turbolizer/package-lock.json +++ b/deps/v8/tools/turbolizer/package-lock.json @@ -1687,9 +1687,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -2344,9 +2344,9 @@ "dev": true }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -2872,9 +2872,9 @@ } }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -3407,35 +3407,14 @@ "dev": true }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "universalify": { diff --git a/deps/v8/tools/turbolizer/src/disassembly-view.ts b/deps/v8/tools/turbolizer/src/disassembly-view.ts index 4b8fc6ea2d..0455437002 100644 --- a/deps/v8/tools/turbolizer/src/disassembly-view.ts +++ b/deps/v8/tools/turbolizer/src/disassembly-view.ts @@ -13,6 +13,7 @@ const toolboxHTML = `
+
`; @@ -26,13 +27,14 @@ export class DisassemblyView extends TextView { offsetSelection: MySelection; showInstructionAddressHandler: () => void; showInstructionBinaryHandler: () => void; + highlightGapInstructionsHandler: () => void; createViewElement() { const pane = document.createElement('div'); pane.setAttribute('id', "disassembly"); pane.innerHTML = `
-       
    +
`; @@ -46,6 +48,19 @@ export class DisassemblyView extends TextView { associateData: (text, fragment: HTMLElement) => { const matches = text.match(/(?
0?x?[0-9a-fA-F]{8,16})(?\s+)(?[0-9a-f]+)(?\s*)/); const offset = Number.parseInt(matches.groups["offset"], 16); + const instructionKind = view.sourceResolver.getInstructionKindForPCOffset(offset); + fragment.dataset.instructionKind = instructionKind; + fragment.title = view.sourceResolver.instructionKindToReadableName(instructionKind); + const blockIds = view.sourceResolver.getBlockIdsForOffset(offset); + const blockIdElement = document.createElement("SPAN"); + blockIdElement.className = "block-id com linkable-text"; + blockIdElement.innerText = ""; + if (blockIds && blockIds.length > 0) { + blockIds.forEach(blockId => view.addHtmlElementForBlockId(blockId, fragment)); + blockIdElement.innerText = `B${blockIds.join(",")}:`; + blockIdElement.dataset.blockId = `${blockIds.join(",")}`; + } + fragment.appendChild(blockIdElement); const addressElement = document.createElement("SPAN"); addressElement.className = "instruction-address"; addressElement.innerText = matches.groups["address"]; @@ -58,11 +73,13 @@ export class DisassemblyView extends TextView { fragment.classList.add('tag'); if (!Number.isNaN(offset)) { - const pcOffset = view.sourceResolver.getKeyPcOffset(offset); + let pcOffset = view.sourceResolver.getKeyPcOffset(offset); + if (pcOffset == -1) pcOffset = Number(offset); fragment.dataset.pcOffset = `${pcOffset}`; addressElement.classList.add('linkable-text'); offsetElement.classList.add('linkable-text'); } + return true; } }; const UNCLASSIFIED_STYLE = { @@ -79,11 +96,20 @@ export class DisassemblyView extends TextView { fragment.innerHTML = text; const replacer = (match, hexOffset) => { const offset = Number.parseInt(hexOffset, 16); - const keyOffset = view.sourceResolver.getKeyPcOffset(offset); - return `${match}`; + let keyOffset = view.sourceResolver.getKeyPcOffset(offset); + if (keyOffset == -1) keyOffset = Number(offset); + const blockIds = view.sourceResolver.getBlockIdsForOffset(offset); + let block = ""; + let blockIdData = ""; + if (blockIds && blockIds.length > 0) { + block = `B${blockIds.join(",")} `; + blockIdData = `data-block-id="${blockIds.join(",")}"`; + } + return `${block}${match}`; }; const html = text.replace(/<.0?x?([0-9a-fA-F]+)>/g, replacer); fragment.innerHTML = html; + return true; } }; const OPCODE_STYLE = { @@ -91,12 +117,14 @@ export class DisassemblyView extends TextView { }; const BLOCK_HEADER_STYLE = { associateData: function (text, fragment) { + if (view.sourceResolver.hasBlockStartInfo()) return false; const matches = /\d+/.exec(text); - if (!matches) return; + if (!matches) return true; const blockId = matches[0]; fragment.dataset.blockId = blockId; fragment.innerHTML = text; fragment.className = "com block"; + return true; } }; const SOURCE_POSITION_HEADER_STYLE = { @@ -135,7 +163,7 @@ export class DisassemblyView extends TextView { const linkHandler = (e: MouseEvent) => { if (!(e.target instanceof HTMLElement)) return; - const offsetAsString = e.target.dataset.pcOffset ? e.target.dataset.pcOffset : e.target.parentElement.dataset.pcOffset; + const offsetAsString = typeof e.target.dataset.pcOffset != "undefined" ? e.target.dataset.pcOffset : e.target.parentElement.dataset.pcOffset; const offset = Number.parseInt(offsetAsString, 10); if ((typeof offsetAsString) != "undefined" && !Number.isNaN(offset)) { view.offsetSelection.select([offset], true); @@ -156,12 +184,12 @@ export class DisassemblyView extends TextView { const linkHandlerBlock = e => { const blockId = e.target.dataset.blockId; - if (typeof blockId != "undefined" && !Number.isNaN(blockId)) { - e.stopPropagation(); + if (typeof blockId != "undefined") { + const blockIds = blockId.split(","); if (!e.shiftKey) { view.selectionHandler.clear(); } - view.blockSelectionHandler.select([blockId], true); + view.blockSelectionHandler.select(blockIds, true); } }; view.divNode.addEventListener('click', linkHandlerBlock); @@ -219,6 +247,17 @@ export class DisassemblyView extends TextView { }; instructionBinaryInput.addEventListener("change", showInstructionBinaryHandler); this.showInstructionBinaryHandler = showInstructionBinaryHandler; + + const highlightGapInstructionsInput: HTMLInputElement = view.divNode.querySelector("#highlight-gap-instructions"); + const lastHighlightGapInstructions = window.sessionStorage.getItem("highlight-gap-instructions"); + highlightGapInstructionsInput.checked = lastHighlightGapInstructions == 'true'; + const highlightGapInstructionsHandler = () => { + window.sessionStorage.setItem("highlight-gap-instructions", `${highlightGapInstructionsInput.checked}`); + view.divNode.classList.toggle("highlight-gap-instructions", highlightGapInstructionsInput.checked); + }; + + highlightGapInstructionsInput.addEventListener("change", highlightGapInstructionsHandler); + this.highlightGapInstructionsHandler = highlightGapInstructionsHandler; } updateSelection(scrollIntoView: boolean = false) { @@ -285,6 +324,7 @@ export class DisassemblyView extends TextView { super.initializeContent(data, null); this.showInstructionAddressHandler(); this.showInstructionBinaryHandler(); + this.highlightGapInstructionsHandler(); console.timeEnd("disassembly-view"); } diff --git a/deps/v8/tools/turbolizer/src/sequence-view.ts b/deps/v8/tools/turbolizer/src/sequence-view.ts index e7691c688f..1319f3ae1e 100644 --- a/deps/v8/tools/turbolizer/src/sequence-view.ts +++ b/deps/v8/tools/turbolizer/src/sequence-view.ts @@ -98,8 +98,10 @@ export class SequenceView extends TextView { const instNodeEl = createElement("div", "instruction-node"); const instId = createElement("div", "instruction-id", instruction.id); + const offsets = view.sourceResolver.instructionToPcOffsets(instruction.id); instId.classList.add("clickable"); instId.dataset.instructionId = instruction.id; + instId.setAttribute("title", `This instruction generated gap code at pc-offset 0x${offsets.gap.toString(16)}, code at pc-offset 0x${offsets.arch.toString(16)}, condition handling at pc-offset 0x${offsets.condition.toString(16)}.`); instNodeEl.appendChild(instId); const instContentsEl = createElement("div", "instruction-contents"); diff --git a/deps/v8/tools/turbolizer/src/source-resolver.ts b/deps/v8/tools/turbolizer/src/source-resolver.ts index 67f9c088a2..588eea5b99 100644 --- a/deps/v8/tools/turbolizer/src/source-resolver.ts +++ b/deps/v8/tools/turbolizer/src/source-resolver.ts @@ -83,6 +83,7 @@ interface InstructionsPhase { instructionOffsetToPCOffset?: any; blockIdtoInstructionRange?: any; nodeIdToInstructionRange?: any; + codeOffsetsInfo?: CodeOffsetsInfo } interface GraphPhase { @@ -103,6 +104,22 @@ export interface Sequence { blocks: Array; } +class CodeOffsetsInfo { + codeStartRegisterCheck: number; + deoptCheck: number; + initPoison: number; + blocksStart: number; + outOfLineCode: number; + deoptimizationExits: number; + pools: number; + jumpTables: number; +} +export class TurbolizerInstructionStartInfo { + gap: number; + arch: number; + condition: number; +} + export class SourceResolver { nodePositionMap: Array; sources: Array; @@ -115,9 +132,12 @@ export class SourceResolver { lineToSourcePositions: Map>; nodeIdToInstructionRange: Array<[number, number]>; blockIdToInstructionRange: Array<[number, number]>; - instructionToPCOffset: Array; + instructionToPCOffset: Array; pcOffsetToInstructions: Map>; pcOffsets: Array; + blockIdToPCOffset: Array; + blockStartPCtoBlockIds: Map>; + codeOffsetsInfo: CodeOffsetsInfo; constructor() { // Maps node ids to source positions. @@ -147,6 +167,17 @@ export class SourceResolver { // Maps PC offsets to instructions. this.pcOffsetToInstructions = new Map(); this.pcOffsets = []; + this.blockIdToPCOffset = []; + this.blockStartPCtoBlockIds = new Map(); + this.codeOffsetsInfo = null; + } + + getBlockIdsForOffset(offset): Array { + return this.blockStartPCtoBlockIds.get(offset); + } + + hasBlockStartInfo() { + return this.blockIdToPCOffset.length > 0; } setSources(sources, mainBackup) { @@ -369,12 +400,18 @@ export class SourceResolver { } readInstructionOffsetToPCOffset(instructionToPCOffset) { - for (const [instruction, offset] of Object.entries(instructionToPCOffset)) { - this.instructionToPCOffset[instruction] = offset; - if (!this.pcOffsetToInstructions.has(offset)) { - this.pcOffsetToInstructions.set(offset, []); + for (const [instruction, numberOrInfo] of Object.entries(instructionToPCOffset)) { + let info: TurbolizerInstructionStartInfo; + if (typeof numberOrInfo == "number") { + info = { gap: numberOrInfo, arch: numberOrInfo, condition: numberOrInfo }; + } else { + info = numberOrInfo; + } + this.instructionToPCOffset[instruction] = info; + if (!this.pcOffsetToInstructions.has(info.gap)) { + this.pcOffsetToInstructions.set(info.gap, []); } - this.pcOffsetToInstructions.get(offset).push(Number(instruction)); + this.pcOffsetToInstructions.get(info.gap).push(Number(instruction)); } this.pcOffsets = Array.from(this.pcOffsetToInstructions.keys()).sort((a, b) => b - a); } @@ -393,15 +430,67 @@ export class SourceResolver { return -1; } - instructionRangeToKeyPcOffsets([start, end]: [number, number]) { + getInstructionKindForPCOffset(offset: number) { + if (this.codeOffsetsInfo) { + if (offset >= this.codeOffsetsInfo.deoptimizationExits) { + if (offset >= this.codeOffsetsInfo.pools) { + return "pools"; + } else if (offset >= this.codeOffsetsInfo.jumpTables) { + return "jump-tables"; + } else { + return "deoptimization-exits"; + } + } + if (offset < this.codeOffsetsInfo.deoptCheck) { + return "code-start-register"; + } else if (offset < this.codeOffsetsInfo.initPoison) { + return "deopt-check"; + } else if (offset < this.codeOffsetsInfo.blocksStart) { + return "init-poison"; + } + } + const keyOffset = this.getKeyPcOffset(offset); + if (keyOffset != -1) { + const infos = this.pcOffsetToInstructions.get(keyOffset).map(instrId => this.instructionToPCOffset[instrId]).filter(info => info.gap != info.condition); + if (infos.length > 0) { + const info = infos[0]; + if (!info || info.gap == info.condition) return "unknown"; + if (offset < info.arch) return "gap"; + if (offset < info.condition) return "arch"; + return "condition"; + } + } + return "unknown"; + } + + instructionKindToReadableName(instructionKind) { + switch (instructionKind) { + case "code-start-register": return "Check code register for right value"; + case "deopt-check": return "Check if function was marked for deoptimization"; + case "init-poison": return "Initialization of poison register"; + case "gap": return "Instruction implementing a gap move"; + case "arch": return "Instruction implementing the actual machine operation"; + case "condition": return "Code implementing conditional after instruction"; + case "pools": return "Data in a pool (e.g. constant pool)"; + case "jump-tables": return "Part of a jump table"; + case "deoptimization-exits": return "Jump to deoptimization exit"; + } + return null; + } + + instructionRangeToKeyPcOffsets([start, end]: [number, number]): Array { if (start == end) return [this.instructionToPCOffset[start]]; return this.instructionToPCOffset.slice(start, end); } - instructionsToKeyPcOffsets(instructionIds: Iterable) { + instructionToPcOffsets(instr: number): TurbolizerInstructionStartInfo { + return this.instructionToPCOffset[instr]; + } + + instructionsToKeyPcOffsets(instructionIds: Iterable): Array { const keyPcOffsets = []; for (const instructionId of instructionIds) { - keyPcOffsets.push(this.instructionToPCOffset[instructionId]); + keyPcOffsets.push(this.instructionToPCOffset[instructionId].gap); } return keyPcOffsets; } @@ -447,6 +536,15 @@ export class SourceResolver { switch (phase.type) { case 'disassembly': this.disassemblyPhase = phase; + if (phase['blockIdToOffset']) { + for (const [blockId, pc] of Object.entries(phase['blockIdToOffset'])) { + this.blockIdToPCOffset[blockId] = pc; + if (!this.blockStartPCtoBlockIds.has(pc)) { + this.blockStartPCtoBlockIds.set(pc, []); + } + this.blockStartPCtoBlockIds.get(pc).push(Number(blockId)); + } + } break; case 'schedule': this.phaseNames.set(phase.name, this.phases.length); @@ -466,6 +564,9 @@ export class SourceResolver { if (phase.instructionOffsetToPCOffset) { this.readInstructionOffsetToPCOffset(phase.instructionOffsetToPCOffset); } + if (phase.codeOffsetsInfo) { + this.codeOffsetsInfo = phase.codeOffsetsInfo; + } break; case 'graph': const graphPhase: GraphPhase = Object.assign(phase, { highestNodeId: 0 }); diff --git a/deps/v8/tools/turbolizer/src/text-view.ts b/deps/v8/tools/turbolizer/src/text-view.ts index 41a06eae77..761a16bff4 100644 --- a/deps/v8/tools/turbolizer/src/text-view.ts +++ b/deps/v8/tools/turbolizer/src/text-view.ts @@ -129,6 +129,10 @@ export abstract class TextView extends PhaseView { if (this.divNode.parentNode == null) return; const mkVisible = new ViewElements(this.divNode.parentNode as HTMLElement); const view = this; + const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset]`); + for (const el of elementsToSelect) { + el.classList.toggle("selected", false); + } for (const [blockId, elements] of this.blockIdToHtmlElementsMap.entries()) { const isSelected = view.blockSelection.isSelected(blockId); for (const element of elements) { @@ -136,10 +140,6 @@ export abstract class TextView extends PhaseView { element.classList.toggle("selected", isSelected); } } - const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset]`); - for (const el of elementsToSelect) { - el.classList.toggle("selected", false); - } for (const key of this.nodeIdToHtmlElementsMap.keys()) { for (const element of this.nodeIdToHtmlElementsMap.get(key)) { element.classList.toggle("selected", false); @@ -170,7 +170,9 @@ export abstract class TextView extends PhaseView { const fragment = document.createElement("SPAN"); if (typeof style.associateData == 'function') { - style.associateData(text, fragment); + if (style.associateData(text, fragment) === false) { + return null; + } } else { if (style.css != undefined) { const css = isIterable(style.css) ? style.css : [style.css]; @@ -198,7 +200,7 @@ export abstract class TextView extends PhaseView { const text = matches[0]; if (text != '') { const fragment = view.createFragment(matches[0], style); - result.push(fragment); + if (fragment !== null) result.push(fragment); } line = line.substr(matches[0].length); } diff --git a/deps/v8/tools/turbolizer/turbo-visualizer.css b/deps/v8/tools/turbolizer/turbo-visualizer.css index 216ca13d04..f89e716ce9 100644 --- a/deps/v8/tools/turbolizer/turbo-visualizer.css +++ b/deps/v8/tools/turbolizer/turbo-visualizer.css @@ -696,3 +696,61 @@ text { padding-left: .5ex; outline: 1px dotted grey; } + +ul.disassembly-list .block-id { + width: 4ex; + display: block; + padding-top: 2px; +} + +div.highlight-gap-instructions [data-instruction-kind="gap"]+span+span { + background-color: #FAEEEE; +} + +div.highlight-gap-instructions [data-instruction-kind="arch"]+span+span { + background-color: #EEFFEE; +} + +div.highlight-gap-instructions [data-instruction-kind="condition"]+span+span { + background-color: #FFFFEE; +} + +div.highlight-gap-instructions [data-instruction-kind="gap"] { + background-color: #FAEEEE; +} + +div.highlight-gap-instructions [data-instruction-kind="arch"] { + background-color: #EEFFEE; +} + +div.highlight-gap-instructions [data-instruction-kind="condition"] { + background-color: #FFFFEE; +} + +div.highlight-gap-instructions [data-instruction-kind="deopt-check"] { + background-color: #FAEEFA; +} + +div.highlight-gap-instructions [data-instruction-kind="init-poison"] { + background-color: #EEFFAA; +} + +div.highlight-gap-instructions [data-instruction-kind="pools"] { + background-color: #6AA84F; +} + +div.highlight-gap-instructions [data-instruction-kind="code-start-register"] { + background-color: #FFCCCC; +} + +div.highlight-gap-instructions [data-instruction-kind="deoptimization-exits"] { + background-color: #CCCCFF; +} + +[data-instruction-kind].selected { + background-color: yellow; +} + +div.highlight-gap-instructions [data-instruction-kind].selected { + background-color: yellow; +} diff --git a/deps/v8/tools/v8heapconst.py b/deps/v8/tools/v8heapconst.py index c6c98c04c3..53aaaf74df 100644 --- a/deps/v8/tools/v8heapconst.py +++ b/deps/v8/tools/v8heapconst.py @@ -31,107 +31,105 @@ INSTANCE_TYPES = { 67: "ODDBALL_TYPE", 68: "MAP_TYPE", 69: "CODE_TYPE", - 70: "MUTABLE_HEAP_NUMBER_TYPE", - 71: "FOREIGN_TYPE", - 72: "BYTE_ARRAY_TYPE", - 73: "BYTECODE_ARRAY_TYPE", - 74: "FREE_SPACE_TYPE", - 75: "FIXED_DOUBLE_ARRAY_TYPE", - 76: "FEEDBACK_METADATA_TYPE", - 77: "FILLER_TYPE", - 78: "ACCESS_CHECK_INFO_TYPE", - 79: "ACCESSOR_INFO_TYPE", - 80: "ACCESSOR_PAIR_TYPE", - 81: "ALIASED_ARGUMENTS_ENTRY_TYPE", - 82: "ALLOCATION_MEMENTO_TYPE", - 83: "ARRAY_BOILERPLATE_DESCRIPTION_TYPE", - 84: "ASM_WASM_DATA_TYPE", - 85: "ASYNC_GENERATOR_REQUEST_TYPE", - 86: "CLASS_POSITIONS_TYPE", - 87: "DEBUG_INFO_TYPE", - 88: "ENUM_CACHE_TYPE", - 89: "FUNCTION_TEMPLATE_INFO_TYPE", - 90: "FUNCTION_TEMPLATE_RARE_DATA_TYPE", - 91: "INTERCEPTOR_INFO_TYPE", - 92: "INTERPRETER_DATA_TYPE", - 93: "OBJECT_TEMPLATE_INFO_TYPE", - 94: "PROMISE_CAPABILITY_TYPE", - 95: "PROMISE_REACTION_TYPE", - 96: "PROTOTYPE_INFO_TYPE", - 97: "SCRIPT_TYPE", - 98: "SOURCE_POSITION_TABLE_WITH_FRAME_CACHE_TYPE", - 99: "SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE", - 100: "STACK_FRAME_INFO_TYPE", - 101: "STACK_TRACE_FRAME_TYPE", - 102: "TEMPLATE_OBJECT_DESCRIPTION_TYPE", - 103: "TUPLE2_TYPE", - 104: "TUPLE3_TYPE", - 105: "WASM_CAPI_FUNCTION_DATA_TYPE", - 106: "WASM_DEBUG_INFO_TYPE", - 107: "WASM_EXCEPTION_TAG_TYPE", - 108: "WASM_EXPORTED_FUNCTION_DATA_TYPE", - 109: "WASM_INDIRECT_FUNCTION_TABLE_TYPE", - 110: "WASM_JS_FUNCTION_DATA_TYPE", - 111: "CALLABLE_TASK_TYPE", - 112: "CALLBACK_TASK_TYPE", - 113: "PROMISE_FULFILL_REACTION_JOB_TASK_TYPE", - 114: "PROMISE_REJECT_REACTION_JOB_TASK_TYPE", - 115: "PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE", - 116: "FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE", - 117: "INTERNAL_CLASS_TYPE", - 118: "SMI_PAIR_TYPE", - 119: "SMI_BOX_TYPE", - 120: "SORT_STATE_TYPE", - 121: "SOURCE_TEXT_MODULE_TYPE", - 122: "SYNTHETIC_MODULE_TYPE", - 123: "ALLOCATION_SITE_TYPE", - 124: "EMBEDDER_DATA_ARRAY_TYPE", - 125: "FIXED_ARRAY_TYPE", - 126: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE", - 127: "CLOSURE_FEEDBACK_CELL_ARRAY_TYPE", - 128: "HASH_TABLE_TYPE", - 129: "ORDERED_HASH_MAP_TYPE", - 130: "ORDERED_HASH_SET_TYPE", - 131: "ORDERED_NAME_DICTIONARY_TYPE", - 132: "NAME_DICTIONARY_TYPE", - 133: "GLOBAL_DICTIONARY_TYPE", - 134: "NUMBER_DICTIONARY_TYPE", - 135: "SIMPLE_NUMBER_DICTIONARY_TYPE", - 136: "STRING_TABLE_TYPE", - 137: "EPHEMERON_HASH_TABLE_TYPE", - 138: "SCOPE_INFO_TYPE", - 139: "SCRIPT_CONTEXT_TABLE_TYPE", - 140: "AWAIT_CONTEXT_TYPE", - 141: "BLOCK_CONTEXT_TYPE", - 142: "CATCH_CONTEXT_TYPE", - 143: "DEBUG_EVALUATE_CONTEXT_TYPE", - 144: "EVAL_CONTEXT_TYPE", - 145: "FUNCTION_CONTEXT_TYPE", - 146: "MODULE_CONTEXT_TYPE", - 147: "NATIVE_CONTEXT_TYPE", - 148: "SCRIPT_CONTEXT_TYPE", - 149: "WITH_CONTEXT_TYPE", - 150: "WEAK_FIXED_ARRAY_TYPE", - 151: "TRANSITION_ARRAY_TYPE", - 152: "CALL_HANDLER_INFO_TYPE", - 153: "CELL_TYPE", - 154: "CODE_DATA_CONTAINER_TYPE", - 155: "DESCRIPTOR_ARRAY_TYPE", - 156: "FEEDBACK_CELL_TYPE", - 157: "FEEDBACK_VECTOR_TYPE", - 158: "LOAD_HANDLER_TYPE", - 159: "PREPARSE_DATA_TYPE", - 160: "PROPERTY_ARRAY_TYPE", - 161: "PROPERTY_CELL_TYPE", - 162: "SHARED_FUNCTION_INFO_TYPE", - 163: "SMALL_ORDERED_HASH_MAP_TYPE", - 164: "SMALL_ORDERED_HASH_SET_TYPE", - 165: "SMALL_ORDERED_NAME_DICTIONARY_TYPE", - 166: "STORE_HANDLER_TYPE", - 167: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE", - 168: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE", - 169: "WEAK_ARRAY_LIST_TYPE", - 170: "WEAK_CELL_TYPE", + 70: "FOREIGN_TYPE", + 71: "BYTE_ARRAY_TYPE", + 72: "BYTECODE_ARRAY_TYPE", + 73: "FREE_SPACE_TYPE", + 74: "FIXED_DOUBLE_ARRAY_TYPE", + 75: "FEEDBACK_METADATA_TYPE", + 76: "FILLER_TYPE", + 77: "ACCESS_CHECK_INFO_TYPE", + 78: "ACCESSOR_INFO_TYPE", + 79: "ACCESSOR_PAIR_TYPE", + 80: "ALIASED_ARGUMENTS_ENTRY_TYPE", + 81: "ALLOCATION_MEMENTO_TYPE", + 82: "ARRAY_BOILERPLATE_DESCRIPTION_TYPE", + 83: "ASM_WASM_DATA_TYPE", + 84: "ASYNC_GENERATOR_REQUEST_TYPE", + 85: "CLASS_POSITIONS_TYPE", + 86: "DEBUG_INFO_TYPE", + 87: "ENUM_CACHE_TYPE", + 88: "FUNCTION_TEMPLATE_INFO_TYPE", + 89: "FUNCTION_TEMPLATE_RARE_DATA_TYPE", + 90: "INTERCEPTOR_INFO_TYPE", + 91: "INTERPRETER_DATA_TYPE", + 92: "OBJECT_TEMPLATE_INFO_TYPE", + 93: "PROMISE_CAPABILITY_TYPE", + 94: "PROMISE_REACTION_TYPE", + 95: "PROTOTYPE_INFO_TYPE", + 96: "SCRIPT_TYPE", + 97: "SOURCE_POSITION_TABLE_WITH_FRAME_CACHE_TYPE", + 98: "SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE", + 99: "STACK_FRAME_INFO_TYPE", + 100: "STACK_TRACE_FRAME_TYPE", + 101: "TEMPLATE_OBJECT_DESCRIPTION_TYPE", + 102: "TUPLE2_TYPE", + 103: "TUPLE3_TYPE", + 104: "WASM_CAPI_FUNCTION_DATA_TYPE", + 105: "WASM_DEBUG_INFO_TYPE", + 106: "WASM_EXCEPTION_TAG_TYPE", + 107: "WASM_EXPORTED_FUNCTION_DATA_TYPE", + 108: "WASM_INDIRECT_FUNCTION_TABLE_TYPE", + 109: "WASM_JS_FUNCTION_DATA_TYPE", + 110: "CALLABLE_TASK_TYPE", + 111: "CALLBACK_TASK_TYPE", + 112: "PROMISE_FULFILL_REACTION_JOB_TASK_TYPE", + 113: "PROMISE_REJECT_REACTION_JOB_TASK_TYPE", + 114: "PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE", + 115: "INTERNAL_CLASS_TYPE", + 116: "SMI_PAIR_TYPE", + 117: "SMI_BOX_TYPE", + 118: "SORT_STATE_TYPE", + 119: "SOURCE_TEXT_MODULE_TYPE", + 120: "SYNTHETIC_MODULE_TYPE", + 121: "ALLOCATION_SITE_TYPE", + 122: "EMBEDDER_DATA_ARRAY_TYPE", + 123: "FIXED_ARRAY_TYPE", + 124: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE", + 125: "CLOSURE_FEEDBACK_CELL_ARRAY_TYPE", + 126: "HASH_TABLE_TYPE", + 127: "ORDERED_HASH_MAP_TYPE", + 128: "ORDERED_HASH_SET_TYPE", + 129: "ORDERED_NAME_DICTIONARY_TYPE", + 130: "NAME_DICTIONARY_TYPE", + 131: "GLOBAL_DICTIONARY_TYPE", + 132: "NUMBER_DICTIONARY_TYPE", + 133: "SIMPLE_NUMBER_DICTIONARY_TYPE", + 134: "STRING_TABLE_TYPE", + 135: "EPHEMERON_HASH_TABLE_TYPE", + 136: "SCOPE_INFO_TYPE", + 137: "SCRIPT_CONTEXT_TABLE_TYPE", + 138: "AWAIT_CONTEXT_TYPE", + 139: "BLOCK_CONTEXT_TYPE", + 140: "CATCH_CONTEXT_TYPE", + 141: "DEBUG_EVALUATE_CONTEXT_TYPE", + 142: "EVAL_CONTEXT_TYPE", + 143: "FUNCTION_CONTEXT_TYPE", + 144: "MODULE_CONTEXT_TYPE", + 145: "NATIVE_CONTEXT_TYPE", + 146: "SCRIPT_CONTEXT_TYPE", + 147: "WITH_CONTEXT_TYPE", + 148: "WEAK_FIXED_ARRAY_TYPE", + 149: "TRANSITION_ARRAY_TYPE", + 150: "CALL_HANDLER_INFO_TYPE", + 151: "CELL_TYPE", + 152: "CODE_DATA_CONTAINER_TYPE", + 153: "DESCRIPTOR_ARRAY_TYPE", + 154: "FEEDBACK_CELL_TYPE", + 155: "FEEDBACK_VECTOR_TYPE", + 156: "LOAD_HANDLER_TYPE", + 157: "PREPARSE_DATA_TYPE", + 158: "PROPERTY_ARRAY_TYPE", + 159: "PROPERTY_CELL_TYPE", + 160: "SHARED_FUNCTION_INFO_TYPE", + 161: "SMALL_ORDERED_HASH_MAP_TYPE", + 162: "SMALL_ORDERED_HASH_SET_TYPE", + 163: "SMALL_ORDERED_NAME_DICTIONARY_TYPE", + 164: "STORE_HANDLER_TYPE", + 165: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE", + 166: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE", + 167: "WEAK_ARRAY_LIST_TYPE", + 168: "WEAK_CELL_TYPE", 1024: "JS_PROXY_TYPE", 1025: "JS_GLOBAL_OBJECT_TYPE", 1026: "JS_GLOBAL_PROXY_TYPE", @@ -192,237 +190,237 @@ INSTANCE_TYPES = { # List of known V8 maps. KNOWN_MAPS = { - ("read_only_space", 0x00111): (74, "FreeSpaceMap"), - ("read_only_space", 0x00161): (68, "MetaMap"), - ("read_only_space", 0x001e1): (67, "NullMap"), - ("read_only_space", 0x00249): (155, "DescriptorArrayMap"), - ("read_only_space", 0x002a9): (150, "WeakFixedArrayMap"), - ("read_only_space", 0x002f9): (77, "OnePointerFillerMap"), - ("read_only_space", 0x00349): (77, "TwoPointerFillerMap"), - ("read_only_space", 0x003c9): (67, "UninitializedMap"), - ("read_only_space", 0x00439): (8, "OneByteInternalizedStringMap"), - ("read_only_space", 0x004d9): (67, "UndefinedMap"), - ("read_only_space", 0x00539): (65, "HeapNumberMap"), - ("read_only_space", 0x005b9): (67, "TheHoleMap"), - ("read_only_space", 0x00661): (67, "BooleanMap"), - ("read_only_space", 0x00739): (72, "ByteArrayMap"), - ("read_only_space", 0x00789): (125, "FixedArrayMap"), - ("read_only_space", 0x007d9): (125, "FixedCOWArrayMap"), - ("read_only_space", 0x00829): (128, "HashTableMap"), - ("read_only_space", 0x00879): (64, "SymbolMap"), - ("read_only_space", 0x008c9): (40, "OneByteStringMap"), - ("read_only_space", 0x00919): (138, "ScopeInfoMap"), - ("read_only_space", 0x00969): (162, "SharedFunctionInfoMap"), - ("read_only_space", 0x009b9): (69, "CodeMap"), - ("read_only_space", 0x00a09): (145, "FunctionContextMap"), - ("read_only_space", 0x00a59): (153, "CellMap"), - ("read_only_space", 0x00aa9): (161, "GlobalPropertyCellMap"), - ("read_only_space", 0x00af9): (71, "ForeignMap"), - ("read_only_space", 0x00b49): (151, "TransitionArrayMap"), - ("read_only_space", 0x00b99): (157, "FeedbackVectorMap"), - ("read_only_space", 0x00c39): (67, "ArgumentsMarkerMap"), - ("read_only_space", 0x00cd9): (67, "ExceptionMap"), - ("read_only_space", 0x00d79): (67, "TerminationExceptionMap"), - ("read_only_space", 0x00e21): (67, "OptimizedOutMap"), - ("read_only_space", 0x00ec1): (67, "StaleRegisterMap"), - ("read_only_space", 0x00f31): (147, "NativeContextMap"), - ("read_only_space", 0x00f81): (146, "ModuleContextMap"), - ("read_only_space", 0x00fd1): (144, "EvalContextMap"), - ("read_only_space", 0x01021): (148, "ScriptContextMap"), - ("read_only_space", 0x01071): (140, "AwaitContextMap"), - ("read_only_space", 0x010c1): (141, "BlockContextMap"), - ("read_only_space", 0x01111): (142, "CatchContextMap"), - ("read_only_space", 0x01161): (149, "WithContextMap"), - ("read_only_space", 0x011b1): (143, "DebugEvaluateContextMap"), - ("read_only_space", 0x01201): (139, "ScriptContextTableMap"), - ("read_only_space", 0x01251): (127, "ClosureFeedbackCellArrayMap"), - ("read_only_space", 0x012a1): (76, "FeedbackMetadataArrayMap"), - ("read_only_space", 0x012f1): (125, "ArrayListMap"), - ("read_only_space", 0x01341): (66, "BigIntMap"), - ("read_only_space", 0x01391): (126, "ObjectBoilerplateDescriptionMap"), - ("read_only_space", 0x013e1): (73, "BytecodeArrayMap"), - ("read_only_space", 0x01431): (154, "CodeDataContainerMap"), - ("read_only_space", 0x01481): (75, "FixedDoubleArrayMap"), - ("read_only_space", 0x014d1): (133, "GlobalDictionaryMap"), - ("read_only_space", 0x01521): (156, "ManyClosuresCellMap"), - ("read_only_space", 0x01571): (125, "ModuleInfoMap"), - ("read_only_space", 0x015c1): (70, "MutableHeapNumberMap"), - ("read_only_space", 0x01611): (132, "NameDictionaryMap"), - ("read_only_space", 0x01661): (156, "NoClosuresCellMap"), - ("read_only_space", 0x016b1): (134, "NumberDictionaryMap"), - ("read_only_space", 0x01701): (156, "OneClosureCellMap"), - ("read_only_space", 0x01751): (129, "OrderedHashMapMap"), - ("read_only_space", 0x017a1): (130, "OrderedHashSetMap"), - ("read_only_space", 0x017f1): (131, "OrderedNameDictionaryMap"), - ("read_only_space", 0x01841): (159, "PreparseDataMap"), - ("read_only_space", 0x01891): (160, "PropertyArrayMap"), - ("read_only_space", 0x018e1): (152, "SideEffectCallHandlerInfoMap"), - ("read_only_space", 0x01931): (152, "SideEffectFreeCallHandlerInfoMap"), - ("read_only_space", 0x01981): (152, "NextCallSideEffectFreeCallHandlerInfoMap"), - ("read_only_space", 0x019d1): (135, "SimpleNumberDictionaryMap"), - ("read_only_space", 0x01a21): (125, "SloppyArgumentsElementsMap"), - ("read_only_space", 0x01a71): (163, "SmallOrderedHashMapMap"), - ("read_only_space", 0x01ac1): (164, "SmallOrderedHashSetMap"), - ("read_only_space", 0x01b11): (165, "SmallOrderedNameDictionaryMap"), - ("read_only_space", 0x01b61): (121, "SourceTextModuleMap"), - ("read_only_space", 0x01bb1): (136, "StringTableMap"), - ("read_only_space", 0x01c01): (122, "SyntheticModuleMap"), - ("read_only_space", 0x01c51): (167, "UncompiledDataWithoutPreparseDataMap"), - ("read_only_space", 0x01ca1): (168, "UncompiledDataWithPreparseDataMap"), - ("read_only_space", 0x01cf1): (169, "WeakArrayListMap"), - ("read_only_space", 0x01d41): (137, "EphemeronHashTableMap"), - ("read_only_space", 0x01d91): (124, "EmbedderDataArrayMap"), - ("read_only_space", 0x01de1): (170, "WeakCellMap"), - ("read_only_space", 0x01e31): (58, "NativeSourceStringMap"), - ("read_only_space", 0x01e81): (32, "StringMap"), - ("read_only_space", 0x01ed1): (41, "ConsOneByteStringMap"), - ("read_only_space", 0x01f21): (33, "ConsStringMap"), - ("read_only_space", 0x01f71): (45, "ThinOneByteStringMap"), - ("read_only_space", 0x01fc1): (37, "ThinStringMap"), - ("read_only_space", 0x02011): (35, "SlicedStringMap"), - ("read_only_space", 0x02061): (43, "SlicedOneByteStringMap"), - ("read_only_space", 0x020b1): (34, "ExternalStringMap"), - ("read_only_space", 0x02101): (42, "ExternalOneByteStringMap"), - ("read_only_space", 0x02151): (50, "UncachedExternalStringMap"), - ("read_only_space", 0x021a1): (0, "InternalizedStringMap"), - ("read_only_space", 0x021f1): (2, "ExternalInternalizedStringMap"), - ("read_only_space", 0x02241): (10, "ExternalOneByteInternalizedStringMap"), - ("read_only_space", 0x02291): (18, "UncachedExternalInternalizedStringMap"), - ("read_only_space", 0x022e1): (26, "UncachedExternalOneByteInternalizedStringMap"), - ("read_only_space", 0x02331): (58, "UncachedExternalOneByteStringMap"), - ("read_only_space", 0x02381): (67, "SelfReferenceMarkerMap"), - ("read_only_space", 0x023e9): (88, "EnumCacheMap"), - ("read_only_space", 0x02489): (83, "ArrayBoilerplateDescriptionMap"), - ("read_only_space", 0x02679): (91, "InterceptorInfoMap"), - ("read_only_space", 0x04e59): (78, "AccessCheckInfoMap"), - ("read_only_space", 0x04ea9): (79, "AccessorInfoMap"), - ("read_only_space", 0x04ef9): (80, "AccessorPairMap"), - ("read_only_space", 0x04f49): (81, "AliasedArgumentsEntryMap"), - ("read_only_space", 0x04f99): (82, "AllocationMementoMap"), - ("read_only_space", 0x04fe9): (84, "AsmWasmDataMap"), - ("read_only_space", 0x05039): (85, "AsyncGeneratorRequestMap"), - ("read_only_space", 0x05089): (86, "ClassPositionsMap"), - ("read_only_space", 0x050d9): (87, "DebugInfoMap"), - ("read_only_space", 0x05129): (89, "FunctionTemplateInfoMap"), - ("read_only_space", 0x05179): (90, "FunctionTemplateRareDataMap"), - ("read_only_space", 0x051c9): (92, "InterpreterDataMap"), - ("read_only_space", 0x05219): (93, "ObjectTemplateInfoMap"), - ("read_only_space", 0x05269): (94, "PromiseCapabilityMap"), - ("read_only_space", 0x052b9): (95, "PromiseReactionMap"), - ("read_only_space", 0x05309): (96, "PrototypeInfoMap"), - ("read_only_space", 0x05359): (97, "ScriptMap"), - ("read_only_space", 0x053a9): (98, "SourcePositionTableWithFrameCacheMap"), - ("read_only_space", 0x053f9): (99, "SourceTextModuleInfoEntryMap"), - ("read_only_space", 0x05449): (100, "StackFrameInfoMap"), - ("read_only_space", 0x05499): (101, "StackTraceFrameMap"), - ("read_only_space", 0x054e9): (102, "TemplateObjectDescriptionMap"), - ("read_only_space", 0x05539): (103, "Tuple2Map"), - ("read_only_space", 0x05589): (104, "Tuple3Map"), - ("read_only_space", 0x055d9): (105, "WasmCapiFunctionDataMap"), - ("read_only_space", 0x05629): (106, "WasmDebugInfoMap"), - ("read_only_space", 0x05679): (107, "WasmExceptionTagMap"), - ("read_only_space", 0x056c9): (108, "WasmExportedFunctionDataMap"), - ("read_only_space", 0x05719): (109, "WasmIndirectFunctionTableMap"), - ("read_only_space", 0x05769): (110, "WasmJSFunctionDataMap"), - ("read_only_space", 0x057b9): (111, "CallableTaskMap"), - ("read_only_space", 0x05809): (112, "CallbackTaskMap"), - ("read_only_space", 0x05859): (113, "PromiseFulfillReactionJobTaskMap"), - ("read_only_space", 0x058a9): (114, "PromiseRejectReactionJobTaskMap"), - ("read_only_space", 0x058f9): (115, "PromiseResolveThenableJobTaskMap"), - ("read_only_space", 0x05949): (116, "FinalizationGroupCleanupJobTaskMap"), - ("read_only_space", 0x05999): (117, "InternalClassMap"), - ("read_only_space", 0x059e9): (118, "SmiPairMap"), - ("read_only_space", 0x05a39): (119, "SmiBoxMap"), - ("read_only_space", 0x05a89): (120, "SortStateMap"), - ("read_only_space", 0x05ad9): (123, "AllocationSiteWithWeakNextMap"), - ("read_only_space", 0x05b29): (123, "AllocationSiteWithoutWeakNextMap"), - ("read_only_space", 0x05b79): (158, "LoadHandler1Map"), - ("read_only_space", 0x05bc9): (158, "LoadHandler2Map"), - ("read_only_space", 0x05c19): (158, "LoadHandler3Map"), - ("read_only_space", 0x05c69): (166, "StoreHandler0Map"), - ("read_only_space", 0x05cb9): (166, "StoreHandler1Map"), - ("read_only_space", 0x05d09): (166, "StoreHandler2Map"), - ("read_only_space", 0x05d59): (166, "StoreHandler3Map"), - ("map_space", 0x00111): (1057, "ExternalMap"), - ("map_space", 0x00161): (1073, "JSMessageObjectMap"), + ("read_only_space", 0x00119): (73, "FreeSpaceMap"), + ("read_only_space", 0x00169): (68, "MetaMap"), + ("read_only_space", 0x001e9): (67, "NullMap"), + ("read_only_space", 0x00251): (153, "DescriptorArrayMap"), + ("read_only_space", 0x002b1): (148, "WeakFixedArrayMap"), + ("read_only_space", 0x00301): (76, "OnePointerFillerMap"), + ("read_only_space", 0x00351): (76, "TwoPointerFillerMap"), + ("read_only_space", 0x003d1): (67, "UninitializedMap"), + ("read_only_space", 0x00441): (8, "OneByteInternalizedStringMap"), + ("read_only_space", 0x004e1): (67, "UndefinedMap"), + ("read_only_space", 0x00541): (65, "HeapNumberMap"), + ("read_only_space", 0x005c1): (67, "TheHoleMap"), + ("read_only_space", 0x00669): (67, "BooleanMap"), + ("read_only_space", 0x00741): (71, "ByteArrayMap"), + ("read_only_space", 0x00791): (123, "FixedArrayMap"), + ("read_only_space", 0x007e1): (123, "FixedCOWArrayMap"), + ("read_only_space", 0x00831): (126, "HashTableMap"), + ("read_only_space", 0x00881): (64, "SymbolMap"), + ("read_only_space", 0x008d1): (40, "OneByteStringMap"), + ("read_only_space", 0x00921): (136, "ScopeInfoMap"), + ("read_only_space", 0x00971): (160, "SharedFunctionInfoMap"), + ("read_only_space", 0x009c1): (69, "CodeMap"), + ("read_only_space", 0x00a11): (143, "FunctionContextMap"), + ("read_only_space", 0x00a61): (151, "CellMap"), + ("read_only_space", 0x00ab1): (159, "GlobalPropertyCellMap"), + ("read_only_space", 0x00b01): (70, "ForeignMap"), + ("read_only_space", 0x00b51): (149, "TransitionArrayMap"), + ("read_only_space", 0x00ba1): (155, "FeedbackVectorMap"), + ("read_only_space", 0x00c41): (67, "ArgumentsMarkerMap"), + ("read_only_space", 0x00ce1): (67, "ExceptionMap"), + ("read_only_space", 0x00d81): (67, "TerminationExceptionMap"), + ("read_only_space", 0x00e29): (67, "OptimizedOutMap"), + ("read_only_space", 0x00ec9): (67, "StaleRegisterMap"), + ("read_only_space", 0x00f39): (145, "NativeContextMap"), + ("read_only_space", 0x00f89): (144, "ModuleContextMap"), + ("read_only_space", 0x00fd9): (142, "EvalContextMap"), + ("read_only_space", 0x01029): (146, "ScriptContextMap"), + ("read_only_space", 0x01079): (138, "AwaitContextMap"), + ("read_only_space", 0x010c9): (139, "BlockContextMap"), + ("read_only_space", 0x01119): (140, "CatchContextMap"), + ("read_only_space", 0x01169): (147, "WithContextMap"), + ("read_only_space", 0x011b9): (141, "DebugEvaluateContextMap"), + ("read_only_space", 0x01209): (137, "ScriptContextTableMap"), + ("read_only_space", 0x01259): (125, "ClosureFeedbackCellArrayMap"), + ("read_only_space", 0x012a9): (75, "FeedbackMetadataArrayMap"), + ("read_only_space", 0x012f9): (123, "ArrayListMap"), + ("read_only_space", 0x01349): (66, "BigIntMap"), + ("read_only_space", 0x01399): (124, "ObjectBoilerplateDescriptionMap"), + ("read_only_space", 0x013e9): (72, "BytecodeArrayMap"), + ("read_only_space", 0x01439): (152, "CodeDataContainerMap"), + ("read_only_space", 0x01489): (74, "FixedDoubleArrayMap"), + ("read_only_space", 0x014d9): (131, "GlobalDictionaryMap"), + ("read_only_space", 0x01529): (154, "ManyClosuresCellMap"), + ("read_only_space", 0x01579): (123, "ModuleInfoMap"), + ("read_only_space", 0x015c9): (130, "NameDictionaryMap"), + ("read_only_space", 0x01619): (154, "NoClosuresCellMap"), + ("read_only_space", 0x01669): (132, "NumberDictionaryMap"), + ("read_only_space", 0x016b9): (154, "OneClosureCellMap"), + ("read_only_space", 0x01709): (127, "OrderedHashMapMap"), + ("read_only_space", 0x01759): (128, "OrderedHashSetMap"), + ("read_only_space", 0x017a9): (129, "OrderedNameDictionaryMap"), + ("read_only_space", 0x017f9): (157, "PreparseDataMap"), + ("read_only_space", 0x01849): (158, "PropertyArrayMap"), + ("read_only_space", 0x01899): (150, "SideEffectCallHandlerInfoMap"), + ("read_only_space", 0x018e9): (150, "SideEffectFreeCallHandlerInfoMap"), + ("read_only_space", 0x01939): (150, "NextCallSideEffectFreeCallHandlerInfoMap"), + ("read_only_space", 0x01989): (133, "SimpleNumberDictionaryMap"), + ("read_only_space", 0x019d9): (123, "SloppyArgumentsElementsMap"), + ("read_only_space", 0x01a29): (161, "SmallOrderedHashMapMap"), + ("read_only_space", 0x01a79): (162, "SmallOrderedHashSetMap"), + ("read_only_space", 0x01ac9): (163, "SmallOrderedNameDictionaryMap"), + ("read_only_space", 0x01b19): (119, "SourceTextModuleMap"), + ("read_only_space", 0x01b69): (134, "StringTableMap"), + ("read_only_space", 0x01bb9): (120, "SyntheticModuleMap"), + ("read_only_space", 0x01c09): (165, "UncompiledDataWithoutPreparseDataMap"), + ("read_only_space", 0x01c59): (166, "UncompiledDataWithPreparseDataMap"), + ("read_only_space", 0x01ca9): (167, "WeakArrayListMap"), + ("read_only_space", 0x01cf9): (135, "EphemeronHashTableMap"), + ("read_only_space", 0x01d49): (122, "EmbedderDataArrayMap"), + ("read_only_space", 0x01d99): (168, "WeakCellMap"), + ("read_only_space", 0x01de9): (58, "NativeSourceStringMap"), + ("read_only_space", 0x01e39): (32, "StringMap"), + ("read_only_space", 0x01e89): (41, "ConsOneByteStringMap"), + ("read_only_space", 0x01ed9): (33, "ConsStringMap"), + ("read_only_space", 0x01f29): (45, "ThinOneByteStringMap"), + ("read_only_space", 0x01f79): (37, "ThinStringMap"), + ("read_only_space", 0x01fc9): (35, "SlicedStringMap"), + ("read_only_space", 0x02019): (43, "SlicedOneByteStringMap"), + ("read_only_space", 0x02069): (34, "ExternalStringMap"), + ("read_only_space", 0x020b9): (42, "ExternalOneByteStringMap"), + ("read_only_space", 0x02109): (50, "UncachedExternalStringMap"), + ("read_only_space", 0x02159): (0, "InternalizedStringMap"), + ("read_only_space", 0x021a9): (2, "ExternalInternalizedStringMap"), + ("read_only_space", 0x021f9): (10, "ExternalOneByteInternalizedStringMap"), + ("read_only_space", 0x02249): (18, "UncachedExternalInternalizedStringMap"), + ("read_only_space", 0x02299): (26, "UncachedExternalOneByteInternalizedStringMap"), + ("read_only_space", 0x022e9): (58, "UncachedExternalOneByteStringMap"), + ("read_only_space", 0x02339): (67, "SelfReferenceMarkerMap"), + ("read_only_space", 0x023a1): (87, "EnumCacheMap"), + ("read_only_space", 0x02441): (82, "ArrayBoilerplateDescriptionMap"), + ("read_only_space", 0x02631): (90, "InterceptorInfoMap"), + ("read_only_space", 0x04eb1): (77, "AccessCheckInfoMap"), + ("read_only_space", 0x04f01): (78, "AccessorInfoMap"), + ("read_only_space", 0x04f51): (79, "AccessorPairMap"), + ("read_only_space", 0x04fa1): (80, "AliasedArgumentsEntryMap"), + ("read_only_space", 0x04ff1): (81, "AllocationMementoMap"), + ("read_only_space", 0x05041): (83, "AsmWasmDataMap"), + ("read_only_space", 0x05091): (84, "AsyncGeneratorRequestMap"), + ("read_only_space", 0x050e1): (85, "ClassPositionsMap"), + ("read_only_space", 0x05131): (86, "DebugInfoMap"), + ("read_only_space", 0x05181): (88, "FunctionTemplateInfoMap"), + ("read_only_space", 0x051d1): (89, "FunctionTemplateRareDataMap"), + ("read_only_space", 0x05221): (91, "InterpreterDataMap"), + ("read_only_space", 0x05271): (92, "ObjectTemplateInfoMap"), + ("read_only_space", 0x052c1): (93, "PromiseCapabilityMap"), + ("read_only_space", 0x05311): (94, "PromiseReactionMap"), + ("read_only_space", 0x05361): (95, "PrototypeInfoMap"), + ("read_only_space", 0x053b1): (96, "ScriptMap"), + ("read_only_space", 0x05401): (97, "SourcePositionTableWithFrameCacheMap"), + ("read_only_space", 0x05451): (98, "SourceTextModuleInfoEntryMap"), + ("read_only_space", 0x054a1): (99, "StackFrameInfoMap"), + ("read_only_space", 0x054f1): (100, "StackTraceFrameMap"), + ("read_only_space", 0x05541): (101, "TemplateObjectDescriptionMap"), + ("read_only_space", 0x05591): (102, "Tuple2Map"), + ("read_only_space", 0x055e1): (103, "Tuple3Map"), + ("read_only_space", 0x05631): (104, "WasmCapiFunctionDataMap"), + ("read_only_space", 0x05681): (105, "WasmDebugInfoMap"), + ("read_only_space", 0x056d1): (106, "WasmExceptionTagMap"), + ("read_only_space", 0x05721): (107, "WasmExportedFunctionDataMap"), + ("read_only_space", 0x05771): (108, "WasmIndirectFunctionTableMap"), + ("read_only_space", 0x057c1): (109, "WasmJSFunctionDataMap"), + ("read_only_space", 0x05811): (110, "CallableTaskMap"), + ("read_only_space", 0x05861): (111, "CallbackTaskMap"), + ("read_only_space", 0x058b1): (112, "PromiseFulfillReactionJobTaskMap"), + ("read_only_space", 0x05901): (113, "PromiseRejectReactionJobTaskMap"), + ("read_only_space", 0x05951): (114, "PromiseResolveThenableJobTaskMap"), + ("read_only_space", 0x059a1): (115, "InternalClassMap"), + ("read_only_space", 0x059f1): (116, "SmiPairMap"), + ("read_only_space", 0x05a41): (117, "SmiBoxMap"), + ("read_only_space", 0x05a91): (118, "SortStateMap"), + ("read_only_space", 0x05ae1): (121, "AllocationSiteWithWeakNextMap"), + ("read_only_space", 0x05b31): (121, "AllocationSiteWithoutWeakNextMap"), + ("read_only_space", 0x05b81): (156, "LoadHandler1Map"), + ("read_only_space", 0x05bd1): (156, "LoadHandler2Map"), + ("read_only_space", 0x05c21): (156, "LoadHandler3Map"), + ("read_only_space", 0x05c71): (164, "StoreHandler0Map"), + ("read_only_space", 0x05cc1): (164, "StoreHandler1Map"), + ("read_only_space", 0x05d11): (164, "StoreHandler2Map"), + ("read_only_space", 0x05d61): (164, "StoreHandler3Map"), + ("map_space", 0x00119): (1057, "ExternalMap"), + ("map_space", 0x00169): (1073, "JSMessageObjectMap"), } # List of known V8 objects. KNOWN_OBJECTS = { - ("read_only_space", 0x001b1): "NullValue", - ("read_only_space", 0x00231): "EmptyDescriptorArray", - ("read_only_space", 0x00299): "EmptyWeakFixedArray", - ("read_only_space", 0x00399): "UninitializedValue", - ("read_only_space", 0x004a9): "UndefinedValue", - ("read_only_space", 0x00529): "NanValue", - ("read_only_space", 0x00589): "TheHoleValue", - ("read_only_space", 0x00621): "HoleNanValue", - ("read_only_space", 0x00631): "TrueValue", - ("read_only_space", 0x006e1): "FalseValue", - ("read_only_space", 0x00729): "empty_string", - ("read_only_space", 0x00be9): "EmptyScopeInfo", - ("read_only_space", 0x00bf9): "EmptyFixedArray", - ("read_only_space", 0x00c09): "ArgumentsMarker", - ("read_only_space", 0x00ca9): "Exception", - ("read_only_space", 0x00d49): "TerminationException", - ("read_only_space", 0x00df1): "OptimizedOut", - ("read_only_space", 0x00e91): "StaleRegister", - ("read_only_space", 0x023d1): "EmptyEnumCache", - ("read_only_space", 0x02439): "EmptyPropertyArray", - ("read_only_space", 0x02449): "EmptyByteArray", - ("read_only_space", 0x02459): "EmptyObjectBoilerplateDescription", - ("read_only_space", 0x02471): "EmptyArrayBoilerplateDescription", - ("read_only_space", 0x024d9): "EmptyClosureFeedbackCellArray", - ("read_only_space", 0x024e9): "EmptySloppyArgumentsElements", - ("read_only_space", 0x02509): "EmptySlowElementDictionary", - ("read_only_space", 0x02551): "EmptyOrderedHashMap", - ("read_only_space", 0x02579): "EmptyOrderedHashSet", - ("read_only_space", 0x025a1): "EmptyFeedbackMetadata", - ("read_only_space", 0x025b1): "EmptyPropertyCell", - ("read_only_space", 0x025d9): "EmptyPropertyDictionary", - ("read_only_space", 0x02629): "NoOpInterceptorInfo", - ("read_only_space", 0x026c9): "EmptyWeakArrayList", - ("read_only_space", 0x026e1): "InfinityValue", - ("read_only_space", 0x026f1): "MinusZeroValue", - ("read_only_space", 0x02701): "MinusInfinityValue", - ("read_only_space", 0x02711): "SelfReferenceMarker", - ("read_only_space", 0x02769): "OffHeapTrampolineRelocationInfo", - ("read_only_space", 0x02781): "TrampolineTrivialCodeDataContainer", - ("read_only_space", 0x02799): "TrampolinePromiseRejectionCodeDataContainer", - ("read_only_space", 0x027b1): "HashSeed", - ("old_space", 0x00111): "ArgumentsIteratorAccessor", - ("old_space", 0x00181): "ArrayLengthAccessor", - ("old_space", 0x001f1): "BoundFunctionLengthAccessor", - ("old_space", 0x00261): "BoundFunctionNameAccessor", - ("old_space", 0x002d1): "ErrorStackAccessor", - ("old_space", 0x00341): "FunctionArgumentsAccessor", - ("old_space", 0x003b1): "FunctionCallerAccessor", - ("old_space", 0x00421): "FunctionNameAccessor", - ("old_space", 0x00491): "FunctionLengthAccessor", - ("old_space", 0x00501): "FunctionPrototypeAccessor", - ("old_space", 0x00571): "StringLengthAccessor", - ("old_space", 0x005e1): "InvalidPrototypeValidityCell", - ("old_space", 0x005f1): "EmptyScript", - ("old_space", 0x00671): "ManyClosuresCell", - ("old_space", 0x00689): "ArrayConstructorProtector", - ("old_space", 0x00699): "NoElementsProtector", - ("old_space", 0x006c1): "IsConcatSpreadableProtector", - ("old_space", 0x006d1): "ArraySpeciesProtector", - ("old_space", 0x006f9): "TypedArraySpeciesProtector", - ("old_space", 0x00721): "PromiseSpeciesProtector", - ("old_space", 0x00749): "StringLengthProtector", - ("old_space", 0x00759): "ArrayIteratorProtector", - ("old_space", 0x00781): "ArrayBufferDetachingProtector", - ("old_space", 0x007a9): "PromiseHookProtector", - ("old_space", 0x007d1): "PromiseResolveProtector", - ("old_space", 0x007e1): "MapIteratorProtector", - ("old_space", 0x00809): "PromiseThenProtector", - ("old_space", 0x00831): "SetIteratorProtector", - ("old_space", 0x00859): "StringIteratorProtector", - ("old_space", 0x00881): "SingleCharacterStringCache", - ("old_space", 0x01091): "StringSplitCache", - ("old_space", 0x018a1): "RegExpMultipleCache", - ("old_space", 0x020b1): "BuiltinsConstantsTable", + ("read_only_space", 0x001b9): "NullValue", + ("read_only_space", 0x00239): "EmptyDescriptorArray", + ("read_only_space", 0x002a1): "EmptyWeakFixedArray", + ("read_only_space", 0x003a1): "UninitializedValue", + ("read_only_space", 0x004b1): "UndefinedValue", + ("read_only_space", 0x00531): "NanValue", + ("read_only_space", 0x00591): "TheHoleValue", + ("read_only_space", 0x00629): "HoleNanValue", + ("read_only_space", 0x00639): "TrueValue", + ("read_only_space", 0x006e9): "FalseValue", + ("read_only_space", 0x00731): "empty_string", + ("read_only_space", 0x00bf1): "EmptyScopeInfo", + ("read_only_space", 0x00c01): "EmptyFixedArray", + ("read_only_space", 0x00c11): "ArgumentsMarker", + ("read_only_space", 0x00cb1): "Exception", + ("read_only_space", 0x00d51): "TerminationException", + ("read_only_space", 0x00df9): "OptimizedOut", + ("read_only_space", 0x00e99): "StaleRegister", + ("read_only_space", 0x02389): "EmptyEnumCache", + ("read_only_space", 0x023f1): "EmptyPropertyArray", + ("read_only_space", 0x02401): "EmptyByteArray", + ("read_only_space", 0x02411): "EmptyObjectBoilerplateDescription", + ("read_only_space", 0x02429): "EmptyArrayBoilerplateDescription", + ("read_only_space", 0x02491): "EmptyClosureFeedbackCellArray", + ("read_only_space", 0x024a1): "EmptySloppyArgumentsElements", + ("read_only_space", 0x024c1): "EmptySlowElementDictionary", + ("read_only_space", 0x02509): "EmptyOrderedHashMap", + ("read_only_space", 0x02531): "EmptyOrderedHashSet", + ("read_only_space", 0x02559): "EmptyFeedbackMetadata", + ("read_only_space", 0x02569): "EmptyPropertyCell", + ("read_only_space", 0x02591): "EmptyPropertyDictionary", + ("read_only_space", 0x025e1): "NoOpInterceptorInfo", + ("read_only_space", 0x02681): "EmptyWeakArrayList", + ("read_only_space", 0x02699): "InfinityValue", + ("read_only_space", 0x026a9): "MinusZeroValue", + ("read_only_space", 0x026b9): "MinusInfinityValue", + ("read_only_space", 0x026c9): "SelfReferenceMarker", + ("read_only_space", 0x02721): "OffHeapTrampolineRelocationInfo", + ("read_only_space", 0x02739): "TrampolineTrivialCodeDataContainer", + ("read_only_space", 0x02751): "TrampolinePromiseRejectionCodeDataContainer", + ("read_only_space", 0x02769): "GlobalThisBindingScopeInfo", + ("read_only_space", 0x027d1): "EmptyFunctionScopeInfo", + ("read_only_space", 0x02821): "HashSeed", + ("old_space", 0x00119): "ArgumentsIteratorAccessor", + ("old_space", 0x00189): "ArrayLengthAccessor", + ("old_space", 0x001f9): "BoundFunctionLengthAccessor", + ("old_space", 0x00269): "BoundFunctionNameAccessor", + ("old_space", 0x002d9): "ErrorStackAccessor", + ("old_space", 0x00349): "FunctionArgumentsAccessor", + ("old_space", 0x003b9): "FunctionCallerAccessor", + ("old_space", 0x00429): "FunctionNameAccessor", + ("old_space", 0x00499): "FunctionLengthAccessor", + ("old_space", 0x00509): "FunctionPrototypeAccessor", + ("old_space", 0x00579): "StringLengthAccessor", + ("old_space", 0x005e9): "InvalidPrototypeValidityCell", + ("old_space", 0x005f9): "EmptyScript", + ("old_space", 0x00679): "ManyClosuresCell", + ("old_space", 0x00691): "ArrayConstructorProtector", + ("old_space", 0x006a1): "NoElementsProtector", + ("old_space", 0x006c9): "IsConcatSpreadableProtector", + ("old_space", 0x006d9): "ArraySpeciesProtector", + ("old_space", 0x00701): "TypedArraySpeciesProtector", + ("old_space", 0x00729): "PromiseSpeciesProtector", + ("old_space", 0x00751): "StringLengthProtector", + ("old_space", 0x00761): "ArrayIteratorProtector", + ("old_space", 0x00789): "ArrayBufferDetachingProtector", + ("old_space", 0x007b1): "PromiseHookProtector", + ("old_space", 0x007d9): "PromiseResolveProtector", + ("old_space", 0x007e9): "MapIteratorProtector", + ("old_space", 0x00811): "PromiseThenProtector", + ("old_space", 0x00839): "SetIteratorProtector", + ("old_space", 0x00861): "StringIteratorProtector", + ("old_space", 0x00889): "SingleCharacterStringCache", + ("old_space", 0x01099): "StringSplitCache", + ("old_space", 0x018a9): "RegExpMultipleCache", + ("old_space", 0x020b9): "BuiltinsConstantsTable", } # List of known V8 Frame Markers. diff --git a/deps/v8/tools/wasm/update-wasm-spec-tests.sh b/deps/v8/tools/wasm/update-wasm-spec-tests.sh index d029ffe604..01688648eb 100755 --- a/deps/v8/tools/wasm/update-wasm-spec-tests.sh +++ b/deps/v8/tools/wasm/update-wasm-spec-tests.sh @@ -30,6 +30,8 @@ V8_DIR="${TOOLS_WASM_DIR}/../.." SPEC_TEST_DIR=${V8_DIR}/test/wasm-spec-tests TMP_DIR=${SPEC_TEST_DIR}/tmp +JS_API_TEST_DIR=${V8_DIR}/test/wasm-js + log_and_run cd ${V8_DIR} log_and_run rm -rf ${SPEC_TEST_DIR}/tests @@ -40,29 +42,40 @@ log_and_run mkdir ${SPEC_TEST_DIR}/tests/proposals log_and_run rm -rf ${TMP_DIR} log_and_run mkdir ${TMP_DIR} +log_and_run rm -rf ${JS_API_TEST_DIR}/tests +log_and_run mkdir ${JS_API_TEST_DIR}/tests +log_and_run mkdir ${JS_API_TEST_DIR}/tests/proposals + ############################################################################### # Generate the spec tests. ############################################################################### -log_and_run cd ${V8_DIR}/test/wasm-js/data/interpreter +echo Process spec +log_and_run cd ${TMP_DIR} +log_and_run git clone https://github.com/WebAssembly/spec +log_and_run cd spec/interpreter + # The next step requires that ocaml is installed. See the README.md in -# ${V8_DIR}/test/wasm-js/data/interpreter/. +# https://github.com/WebAssembly/spec/tree/master/interpreter/. log_and_run make clean opt -log_and_run cd ${V8_DIR}/test/wasm-js/data/test/core +log_and_run cd ${TMP_DIR}/spec/test/core log_and_run cp *.wast ${SPEC_TEST_DIR}/tests/ -log_and_run ./run.py --wasm ${V8_DIR}/test/wasm-js/data/interpreter/wasm --out ${TMP_DIR} +log_and_run ./run.py --wasm ${TMP_DIR}/spec/interpreter/wasm --out ${TMP_DIR} log_and_run cp ${TMP_DIR}/*.js ${SPEC_TEST_DIR}/tests/ +log_and_run cp -r ${TMP_DIR}/spec/test/js-api/* ${JS_API_TEST_DIR}/tests + ############################################################################### # Generate the proposal tests. ############################################################################### -repos='bulk-memory-operations reference-types' +repos='bulk-memory-operations reference-types js-types' for repo in ${repos}; do echo "Process ${repo}" + echo ">> Process core tests" log_and_run cd ${TMP_DIR} log_and_run git clone https://github.com/WebAssembly/${repo} # Compile the spec interpreter to generate the .js test cases later. @@ -76,13 +89,27 @@ for repo in ${repos}; do for abs_filename in ${TMP_DIR}/${repo}/test/core/*.wast; do rel_filename="$(basename -- $abs_filename)" test_name=${rel_filename%.wast} - spec_filename=${V8_DIR}/test/wasm-js/data/test/core/${rel_filename} + spec_filename=${TMP_DIR}/spec/test/core/${rel_filename} if [ ! -f "$spec_filename" ] || ! cmp -s $abs_filename $spec_filename ; then log_and_run cp ${rel_filename} ${SPEC_TEST_DIR}/tests/proposals/${repo}/ log_and_run ./run.py --wasm ../../interpreter/wasm ${rel_filename} --out _build 2> /dev/null fi done log_and_run cp _build/*.js ${SPEC_TEST_DIR}/tests/proposals/${repo}/ + + echo ">> Process js-api tests" + log_and_run mkdir ${JS_API_TEST_DIR}/tests/proposals/${repo} + log_and_run cp -r ${TMP_DIR}/${repo}/test/js-api/* ${JS_API_TEST_DIR}/tests/proposals/${repo} + # Delete duplicate tests + log_and_run cd ${JS_API_TEST_DIR}/tests + for spec_test_name in $(find ./ -name '*.any.js' -not -wholename '*/proposals/*'); do + proposal_test_name="proposals/${repo}/${spec_test_name}" + if [ -f "$proposal_test_name" ] && cmp -s $spec_test_name $proposal_test_name ; then + log_and_run rm $proposal_test_name + elif [ -f "$proposal_test_name" ]; then + echo "keep" $proposal_test_name + fi + done done ############################################################################### @@ -95,6 +122,10 @@ echo "The following files will get uploaded:" ls -R tests echo +cd ${JS_API_TEST_DIR} +ls -R tests +echo + log_and_run rm -rf ${TMP_DIR} ############################################################################### @@ -111,3 +142,6 @@ echo "* When the script asks you for your project-id, use 0." echo "****************************************************************************" log_and_run cd ${SPEC_TEST_DIR} log_and_run upload_to_google_storage.py -a -b v8-wasm-spec-tests tests + +log_and_run cd ${JS_API_TEST_DIR} +log_and_run upload_to_google_storage.py -a -b v8-wasm-spec-tests tests diff --git a/deps/v8/tools/whitespace.txt b/deps/v8/tools/whitespace.txt index 9a80a32344..1540f5f52a 100644 --- a/deps/v8/tools/whitespace.txt +++ b/deps/v8/tools/whitespace.txt @@ -7,4 +7,6 @@ A Smi balks into a war and says: The doubles heard this and started to unbox. The Smi looked at them when a crazy v8-autoroll account showed up... The autoroller bought a round of Himbeerbrause. Suddenly..... -The bartender starts to shake the bottles.......... +The bartender starts to shake the bottles.............. +I can't add trailing whitespaces, so I'm adding this line. +I'm starting to think that just adding trailing whitespaces might not be bad. diff --git a/deps/v8/tools/windbg.js b/deps/v8/tools/windbg.js index 3df14f4a2e..91877b4c61 100644 --- a/deps/v8/tools/windbg.js +++ b/deps/v8/tools/windbg.js @@ -1,4 +1,4 @@ -// Copyright 2019 the V8 project authors. All rights reserved. +// 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. @@ -11,6 +11,7 @@ =============================================================================*/ function help() { + if (supports_call_command()) { print("--------------------------------------------------------------------"); print(" LIVE debugging only"); print("--------------------------------------------------------------------"); @@ -27,11 +28,22 @@ function help() { print(" !jsbp() or !jsbp"); print(" sets bp in v8::internal::Execution::Call"); print(""); + } + print("--------------------------------------------------------------------"); - print(" Managed heap"); + print(" Setup of the script"); print("--------------------------------------------------------------------"); + print(" !set_module(\"module_name_no_extension\")"); + print(" we'll try the usual suspects for where v8's code might have"); + print(" been linked into, but you can also set it manually,"); + print(" e.g. !set_module(\"v8_for_testing\")"); print(" !set_iso(isolate_address)"); print(" call this function before using !mem or other heap routines"); + print(""); + + print("--------------------------------------------------------------------"); + print(" Managed heap"); + print("--------------------------------------------------------------------"); print(" !mem or !mem(\"space1[ space2 ...]\")"); print(" prints memory chunks from the 'space' owned by the heap in the"); print(" isolate set by !set_iso; valid values for 'space' are:"); @@ -42,15 +54,59 @@ function help() { print(" prints name of the space and address of the MemoryChunk the"); print(" 'address' is from, e.g. !where(0x235cb869f9)"); print(""); + + print("--------------------------------------------------------------------"); + print(" Managed objects"); + print("--------------------------------------------------------------------"); + print(" !jot(tagged_addr, depth)"); + print(" dumps the tree of objects using 'tagged_addr' as a root,"); + print(" assumes that pointer fields are aligned at ptr_size boundary,"); + print(" unspecified depth means 'unlimited',"); + print(" e.g. !jot(0x235cb869f9, 2), !jot 0x235cb869f9"); + print(" !jo_in_range(start_addr, end_addr)"); + print(" prints address/map pointers of objects found inside the range"); + print(" specified by 'start_addr' and 'end_addr', assumes the object"); + print(" pointers to be aligned at ptr_size boundary,"); + print(" e.g. !jo_in_range(0x235cb869f8 - 0x100, 0x235cb869f8 + 0x1a0"); + print(" !jo_prev(address, max_slots = 100)"); + print(" prints address and map pointer of the nearest object within"); + print(" 'max_slots' before the given 'address', assumes the object"); + print(" pointers to be aligned at ptr_size boundary,"); + print(" e.g. !jo_prev 0x235cb869f8, !jo_prev(0x235cb869f9, 16)"); + print(" !jo_next(address, max_slots = 100)"); + print(" prints address and map pointer of the nearest object within"); + print(" 'max_slots' following the given 'address', assumes the object"); + print(" pointers to be aligned at ptr_size boundary,"); + print(" e.g. !jo_next 0x235cb869f8, !jo_next(0x235cb869f9, 20)"); + print(""); + + print("--------------------------------------------------------------------"); + print(" Miscellaneous"); + print("--------------------------------------------------------------------"); + print(" !dp(address, count = 10)"); + print(" similar to the built-in 'dp' command but augments output with"); + print(" more data for values that are managed pointers, note that it"); + print(" aligns the given 'address' at ptr_sized boundary,"); + print(" e.g. !dp 0x235cb869f9, !dp(0x235cb869f9, 500), !dp @rsp"); + print(" !handles(print_handles = false)"); + print(" prints stats for handles, if 'print_handles' is true will"); + print(" output all handles as well,"); + print(" e.g. !handles, !handles(), !handles(true)"); + print(""); + print("--------------------------------------------------------------------"); print(" To run any function from this script (live or postmortem):"); print(""); print(" dx @$scriptContents.function_name(args)"); print(" e.g. dx @$scriptContents.pointer_size()"); - print(" e.g. dx @$scriptContents.module_name(\"v8_for_test\")"); + print(" e.g. dx @$scriptContents.is_map(0x235cb869f9)"); print("--------------------------------------------------------------------"); } +/*============================================================================= + On scrip load +=============================================================================*/ + /*============================================================================= Output =============================================================================*/ @@ -67,27 +123,60 @@ function print_filtered(obj, filter) { } function inspect(s) { - for (var k of Reflect.ownKeys(s)) { - print(k + " => " + Reflect.get(s, k)); + for (let k of Reflect.ownKeys(s)) { + // Attempting to print either of: + // 'Reflect.get(s, k)', 'typeof Reflect.get(s, k)', 's[k]' + // might throw: "Error: Object does not have a size", + // while 'typeof s[k]' returns 'undefined' and prints the full list of + // properties. Oh well... + print(`${k} => ${typeof s[k]}`); } } +function hex(number) { + return `0x${number.toString(16)}`; +} /*============================================================================= Utils (postmortem and live) =============================================================================*/ +// WinDbg wraps large integers into objects that fail isInteger test (and, +// consequently fail isSafeInteger test even if the original value was a safe +// integer). I cannot figure out how to extract the original value from the +// wrapper object so doing it via conversion to a string. Brrr. Ugly. +function int(val) { + if (typeof val === 'number') { + return Number.isInteger(val) ? val : undefined; + } + if (typeof val === 'object') { + let n = parseInt(val.toString()); + return isNaN(n) ? undefined : n; + } + return undefined; +} + +function is_live_session() { + // Assume that there is a single session (not sure how to get multiple ones + // going, maybe, in kernel debugging?). + return (host.namespace.Debugger.Sessions[0].Attributes.Target.IsLiveTarget); +} + +function is_TTD_session() { + // Assume that there is a single session (not sure how to get multiple ones + // going, maybe, in kernel debugging?). + return (host.namespace.Debugger.Sessions[0].Attributes.Target.IsTTDTarget); +} + +function supports_call_command() { + return is_live_session() && !is_TTD_session(); +} + function cast(address, type_name) { return host.createTypedObject(address, module_name(), type_name); } -// Failed to figure out how to get pointer size from the debugger's data model, -// so we parse it out from sizeof(void*) output. function pointer_size() { - let ctl = host.namespace.Debugger.Utility.Control; - let sizeof = ctl.ExecuteCommand("?? sizeof(void*)"); - let output = ""; - for (output of sizeof) {} // unsigned int64 8 - return parseInt(output.trim().split(" ").pop()); + return host.namespace.Debugger.Sessions[0].Attributes.Machine.PointerSize; } function poi(address) { @@ -105,8 +194,7 @@ function get_register(name) { // In debug builds v8 code is compiled into v8.dll, and in release builds // the code is compiled directly into the executable. If you are debugging some -// other embedder, invoke module_name explicitly from the debugger and provide -// the module name to use. +// other embedder, run !set_module and provide the module name to use. const known_exes = ["d8", "unittests", "mksnapshot", "chrome", "chromium"]; let module_name_cache; function module_name(use_this_module) { @@ -138,10 +226,20 @@ function module_name(use_this_module) { } } } + + if (!module_name_cache) { + print(`ERROR. Couldn't determine module name for v8's symbols.`); + print(`Please run !set_module (e.g. "!set_module \"v8_for_testing\"")`); + } return module_name_cache; }; function make_call(fn) { + if (!supports_call_command()) { + print("ERROR: This command is supported in live sessions only!"); + return; + } + // .call resets current frame to the top one, so have to manually remember // and restore it after making the call. let curframe = host.namespace.Debugger.State.DebuggerVariables.curframe; @@ -151,21 +249,6 @@ function make_call(fn) { return output; } -// Skips the meta output about the .call invocation. -function make_call_and_print_return(fn) { - let output = make_call(fn); - let print_line = false; - for (let line of output) { - if (print_line) { - print(line); - break; - } - if (line.includes(".call returns")) { - print_line = true; - } - } -} - /*============================================================================= Wrappers around V8's printing functions and other utils for live-debugging @@ -206,11 +289,11 @@ function print_object_from_handle(handle_to_object) { point at any continuous memory that contains Object pointers. -----------------------------------------------------------------------------*/ function print_objects_array(start_address, count) { + const ptr_size = pointer_size(); let ctl = host.namespace.Debugger.Utility.Control; - let psize = pointer_size(); let addr_int = start_address; for (let i = 0; i < count; i++) { - const addr_hex = `0x${addr_int.toString(16)}`; + const addr_hex = hex(addr_int); // TODO: Tried using createPointerObject but it throws unknown exception // from ChakraCore. Why? @@ -223,7 +306,7 @@ function print_objects_array(start_address, count) { print(`${addr_hex} -> ${deref}`); print_object(deref); - addr_int += psize; + addr_int += ptr_size; } } @@ -245,6 +328,168 @@ function set_isolate_address(addr) { isolate_address = addr; } +function is_map(addr) { + let address = int(addr); + if (!Number.isSafeInteger(address) || address % 2 == 0) return false; + + // the first field in all objects, including maps, is a map pointer, but for + // maps the pointer is always the same - the meta map that points to itself. + const map_addr = int(poi(address - 1)); + if (!Number.isSafeInteger(map_addr)) return false; + + const map_map_addr = int(poi(map_addr - 1)); + if (!Number.isSafeInteger(map_map_addr)) return false; + + return (map_addr === map_map_addr); +} + +function is_likely_object(addr) { + let address = int(addr); + if (!Number.isSafeInteger(address) || address % 2 == 0) return false; + + // the first field in all objects must be a map pointer + return is_map(poi(address - 1)); +} + +function find_object_near(aligned_addr, max_distance, step_op) { + if (!step_op) { + const step = pointer_size(); + const prev = + find_object_near(aligned_addr, max_distance, x => x - step); + const next = + find_object_near(aligned_addr, max_distance, x => x + step); + + if (!prev) return next; + if (!next) return prev; + return (addr - prev <= next - addr) ? prev : next; + } + + let maybe_map_addr = poi(aligned_addr); + let iters = 0; + while (maybe_map_addr && iters < max_distance) { + if (is_map(maybe_map_addr)) { + return aligned_addr; + } + aligned_addr = step_op(aligned_addr); + maybe_map_addr = poi(aligned_addr); + iters++; + } +} + +function find_object_prev(addr, max_distance) { + if (!Number.isSafeInteger(int(addr))) return; + + const ptr_size = pointer_size(); + const aligned_addr = addr - (addr % ptr_size); + return find_object_near(aligned_addr, max_distance, x => x - ptr_size); +} + +function find_object_next(addr, max_distance) { + if (!Number.isSafeInteger(int(addr))) return; + + const ptr_size = pointer_size(); + const aligned_addr = addr - (addr % ptr_size) + ptr_size; + return find_object_near(aligned_addr, max_distance, x => x + ptr_size); +} + +function print_object_prev(addr, max_slots = 100) { + let obj_addr = find_object_prev(addr, max_slots); + if (!obj_addr) { + print( + `No object found within ${max_slots} slots prior to ${hex(addr)}`); + } + else { + print( + `found object: ${hex(obj_addr + 1)} : ${hex(poi(obj_addr))}`); + } +} + +function print_object_next(addr, max_slots = 100) { + let obj_addr = find_object_next(addr, max_slots); + if (!obj_addr) { + print( + `No object found within ${max_slots} slots following ${hex(addr)}`); + } + else { + print( + `found object: ${hex(obj_addr + 1)} : ${hex(poi(obj_addr))}`); + } +} + +// This function assumes that pointers to objects are stored at ptr-size aligned +// boundaries. +function print_objects_in_range(start, end){ + if (!Number.isSafeInteger(int(start)) || !Number.isSafeInteger(int(end))) { + return; + } + + const ptr_size = pointer_size(); + let iters = (end - start) / ptr_size; + let cur = start; + print(`===============================================`); + print(`objects in range ${hex(start)} - ${hex(end)}`); + print(`===============================================`); + let count = 0; + while (cur && cur < end) { + let obj = find_object_next(cur, iters); + if (obj) { + count++; + print(`${hex(obj + 1)} : ${hex(poi(obj))}`); + iters = (end - cur) / ptr_size; + } + cur = obj + ptr_size; + } + print(`===============================================`); + print(`found ${count} objects in range ${hex(start)} - ${hex(end)}`) + print(`===============================================`); +} + +// This function assumes the pointer fields to be ptr-size aligned. +function print_objects_tree(root, depth_limit) { + if(!is_likely_object(root)) { + print(`${hex(root)} doesn't look like an object`); + return; + } + + let path = []; + + function impl(obj, depth, depth_limit) { + const ptr_size = pointer_size(); + // print the current object and its map pointer + const this_obj = + `${" ".repeat(2 * depth)}${hex(obj)} : ${hex(poi(obj - 1))}`; + const cutoff = depth_limit && depth == depth_limit - 1; + print(`${this_obj}${cutoff ? " (...)" : ""}`); + if (cutoff) return; + + path[depth] = obj; + path.length = depth + 1; + let cur = obj - 1 + ptr_size; + + // Scan downwards until an address that is likely to be at the start of + // another object, in which case it's time to pop out from the recursion. + let iter = 0; // an arbitrary guard to avoid hanging the debugger + let seen = new Set(path); + while (!is_likely_object(cur + 1) && iter < 100) { + iter++; + let field = poi(cur); + if (is_likely_object(field)) { + if (seen.has(field)) { + print( + `${" ".repeat(2 * depth + 2)}cycle: ${hex(cur)}->${hex(field)}`); + } + else { + impl(field, depth + 1, depth_limit); + } + } + cur += ptr_size; + } + } + print(`===============================================`); + impl(root, 0, depth_limit); + print(`===============================================`); +} + /*----------------------------------------------------------------------------- Memory in each Space is organized into a linked list of memory chunks -----------------------------------------------------------------------------*/ @@ -262,11 +507,10 @@ function print_memory_chunk_list(space_type, front, top, age_mark) { let cur = front; while (!cur.isNull) { let imm = cur.flags_ & NEVER_EVACUATE ? "*" : " "; - let addr = `0x${cur.address.toString(16)}`; - let area = - `0x${cur.area_start_.toString(16)} - 0x${cur.area_end_.toString(16)}`; + let addr = hex(cur.address); + let area = `${hex(cur.area_start_)} - ${hex(cur.area_end_)}`; let dt = `dt ${addr} ${module_name()}!v8::internal::MemoryChunk`; - print(`${imm} ${addr}:\t ${area} (0x${cur.size_.toString(16)}) : ${dt}`); + print(`${imm} ${addr}:\t ${area} (${hex(cur.size_)}) : ${dt}`); cur = cur.list_node_.next_; } print(""); @@ -307,18 +551,16 @@ function get_chunks() { } function find_chunk(address) { - // if 'address' is greater than Number.MAX_SAFE_INTEGER, comparison ops on it - // throw "Error: 64 bit value loses precision on conversion to number" - try { - let chunks = get_chunks(isolate_address); - for (let c of chunks) { - let chunk = cast(c.address, "v8::internal::MemoryChunk"); - if (address >= chunk.area_start_ && address < chunk.area_end_) { - return c; - } + if (!Number.isSafeInteger(int(address))) return undefined; + + let chunks = get_chunks(isolate_address); + for (let c of chunks) { + let chunk = cast(c.address, "v8::internal::MemoryChunk"); + if (address >= chunk.area_start_ && address < chunk.area_end_) { + return c; } } - catch (e) { } + return undefined; } @@ -391,12 +633,111 @@ function print_owning_space(address) { } let c = find_chunk(address); - let addr = `0x${address.toString(16)}`; if (c) { - print(`${addr} is in ${c.space} (chunk: 0x${c.address.toString(16)})`); + print(`${hex(address)} is in ${c.space} (chunk: ${hex(c.address)})`); } else { - print(`Address ${addr} is not in managed heap`); + print(`Address ${hex(address)} is not in managed heap`); + } +} + +/*----------------------------------------------------------------------------- + +-----------------------------------------------------------------------------*/ +function print_handles_data(print_handles = false) { + if (isolate_address == 0) { + print("Please call !set_iso(isolate_address) first."); + return; + } + + let iso = cast(isolate_address, "v8::internal::Isolate"); + let hsd = iso.handle_scope_data_; + let hsimpl = iso.handle_scope_implementer_; + + // depth level + print(`Nested depth level: ${hsd.level}`); + + // count of handles + const ptr_size = pointer_size(); + let blocks = hsimpl.blocks_; + const block_size = 1022; // v8::internal::KB - 2 + const first_block = blocks.data_.address; + const last_block = (blocks.size_ == 0) + ? first_block + : first_block + ptr_size * (blocks.size_ - 1); + + const count = (blocks.size_ == 0) + ? 0 + : (blocks.size_ - 1) * block_size + + (hsd.next.address - poi(last_block))/ptr_size; + print(`Currently tracking ${count} local handles`); + + // print the handles + if (print_handles && count > 0) { + for (let block = first_block; block < last_block; + block += block_size * ptr_size) { + print(`Handles in block at ${hex(block)}`); + for (let i = 0; i < block_size; i++) { + const location = poi(block + i * ptr_size); + print(` ${hex(location)}->${hex(poi(location))}`); + } + } + + let location = poi(last_block); + print(`Handles in block at ${hex(last_block)}`); + for (let location = poi(last_block); location < hsd.next.address; + location += ptr_size) { + print(` ${hex(location)}->${hex(poi(location))}`); + } + } + + // where will the next handle allocate at? + const prefix = "Next handle's location will be"; + if (hsd.next.address < hsd.limit.address) { + print(`${prefix} at ${hex(hsd.next.address)}`); + } + else if (hsimpl.spare_) { + const location = hsimpl.spare_.address; + print(`${prefix} from the spare block at ${hex(location)}`); + } + else { + print(`${prefix} from a new block to be allocated`); + } +} + +function pad_right(addr) { + let addr_hex = hex(addr); + return `${addr_hex}${" ".repeat(pointer_size() * 2 + 2 - addr_hex.length)}`; +} + +// TODO irinayat: would be nice to identify handles and smi as well +function dp(addr, count = 10) { + if (isolate_address == 0) { + print(`To see where objects are located, run !set_iso.`); + } + + if (!Number.isSafeInteger(int(addr))) { + print(`${hex(addr)} doesn't look like a valid address`); + return; + } + + const ptr_size = pointer_size(); + let aligned_addr = addr - (addr % ptr_size); + let val = poi(aligned_addr); + let iter = 0; + while (val && iter < count) { + const augm_map = is_map(val) ? "map" : ""; + const augm_obj = is_likely_object(val) && !is_map(val) ? "obj" : ""; + const augm_other = !is_map(val) && !is_likely_object(val) ? "val" : ""; + let c = find_chunk(val); + const augm_space = c ? ` in ${c.space}` : ""; + const augm = `${augm_map}${augm_obj}${augm_other}${augm_space}`; + + print(`${pad_right(aligned_addr)} ${pad_right(val)} ${augm}`); + + aligned_addr += ptr_size; + val = poi(aligned_addr); + iter++; } } @@ -412,8 +753,17 @@ function initializeScript() { new host.functionAlias(print_js_stack, "jst"), new host.functionAlias(set_isolate_address, "set_iso"), + new host.functionAlias(module_name, "set_module"), new host.functionAlias(print_memory, "mem"), new host.functionAlias(print_owning_space, "where"), + new host.functionAlias(print_handles_data, "handles"), + + new host.functionAlias(print_object_prev, "jo_prev"), + new host.functionAlias(print_object_next, "jo_next"), + new host.functionAlias(print_objects_in_range, "jo_in_range"), + new host.functionAlias(print_objects_tree, "jot"), + + new host.functionAlias(dp, "dp"), new host.functionAlias(set_user_js_bp, "jsbp"), ] -- cgit v1.2.3