[diagnostics] Support --turbo-profiling for builtins
Currently, if d8 is run with the --turbo-profiling flag, it prints info about every TurboFan-compiled function. This info includes the number of times that each basic block in the function was run. It also includes text representations of the function's schedule and code, so that the person reading the output can associate counters with blocks of code. The data about each function is currently stored in a BasicBlockProfiler::Data instance, which is attached to a list owned by the singleton BasicBlockProfiler. Each Data contains an std::vector<uint32_t> which represents how many times each block in the function has executed. The generated code for each block uses a raw pointer into the storage of that vector to implement incrementing the counter. With this change, if you compile with v8_enable_builtins_profiling and then run with --turbo-profiling, d8 will print that same info about builtins too. In order to generate code that can survive being serialized to a snapshot and reloaded, this change uses counters in the JS heap instead of a std::vector outside the JS heap. The steps for instrumentation are as follows: 1. Between scheduling and instruction selection, add code to increment the counter for each block. The counters array doesn't yet exist at this point, and allocation is disallowed, so at this point the code refers to a special marker value. 2. During finalization of the code, allocate a BasicBlockProfilingData object on the JS heap containing data equivalent to what is stored in BasicBlockProfiler::Data. This includes a ByteArray that is big enough to store the counters for each block. 3. Patch the reference in the BuiltinsConstantsTableBuilder so that instead of referring to the marker object, it now refers to this ByteArray. Also add the BasicBlockProfilingData object to a list that is attached to the heap roots so it can be easily accessed for printing. Because these steps include modifying the BuiltinsConstantsTableBuilder, this procedure is only applicable to builtins. Runtime-generated code still uses raw pointers into std::vector instances. In order to keep divergence between these code paths to a minimum, most work is done referring to instances of BasicBlockProfiler::Data (the C++ class), and functions are provided to copy back and forth between that type and BasicBlockProfilingData (the JS heap object). This change is intended only to make --turbo-profiling work consistently on more kinds of functions, but with some further work, this data could form the basis for: - code coverage info for fuzzers, and/or - hot-path info for profile-guided optimization. Bug: v8:10470, v8:9119 Change-Id: Ib556a5bc3abe67cdaa2e3ee62702a2a08b11cb61 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2159738 Commit-Queue: Seth Brenith <seth.brenith@microsoft.com> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#67944}
This commit is contained in:
parent
16a23e9aea
commit
18c73676c1
9
BUILD.gn
9
BUILD.gn
@ -130,6 +130,11 @@ declare_args() {
|
||||
# Sets -dV8_ARRAY_BUFFER_EXTENSION
|
||||
v8_enable_array_buffer_extension = true
|
||||
|
||||
# Runs mksnapshot with --turbo-profiling. After building in this
|
||||
# configuration, any subsequent run of d8 with --turbo-profiling will output
|
||||
# information about both runtime-generated code and builtins.
|
||||
v8_enable_builtins_profiling = false
|
||||
|
||||
# Enables various testing features.
|
||||
v8_enable_test_features = ""
|
||||
|
||||
@ -1410,6 +1415,10 @@ template("run_mksnapshot") {
|
||||
rebase_path("$target_gen_dir/embedded${suffix}.S", root_build_dir),
|
||||
]
|
||||
|
||||
if (v8_enable_builtins_profiling) {
|
||||
args += [ "--turbo-profiling" ]
|
||||
}
|
||||
|
||||
# This is needed to distinguish between generating code for the simulator
|
||||
# and cross-compiling. The latter may need to run code on the host with the
|
||||
# simulator but cannot use simulator-specific instructions.
|
||||
|
@ -57,24 +57,30 @@ uint32_t BuiltinsConstantsTableBuilder::AddObject(Handle<Object> object) {
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinsConstantsTableBuilder::PatchSelfReference(
|
||||
Handle<Object> self_reference, Handle<Code> code_object) {
|
||||
#ifdef DEBUG
|
||||
namespace {
|
||||
void CheckPreconditionsForPatching(Isolate* isolate,
|
||||
Handle<Object> replacement_object) {
|
||||
// Roots must not be inserted into the constants table as they are already
|
||||
// accessibly from the root list.
|
||||
// accessible from the root list.
|
||||
RootIndex root_list_index;
|
||||
DCHECK(!isolate_->roots_table().IsRootHandle(code_object, &root_list_index));
|
||||
DCHECK(!isolate->roots_table().IsRootHandle(replacement_object,
|
||||
&root_list_index));
|
||||
USE(root_list_index);
|
||||
|
||||
// Not yet finalized.
|
||||
DCHECK_EQ(ReadOnlyRoots(isolate_).empty_fixed_array(),
|
||||
isolate_->heap()->builtins_constants_table());
|
||||
DCHECK_EQ(ReadOnlyRoots(isolate).empty_fixed_array(),
|
||||
isolate->heap()->builtins_constants_table());
|
||||
|
||||
DCHECK(isolate_->IsGeneratingEmbeddedBuiltins());
|
||||
DCHECK(isolate->IsGeneratingEmbeddedBuiltins());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void BuiltinsConstantsTableBuilder::PatchSelfReference(
|
||||
Handle<Object> self_reference, Handle<Code> code_object) {
|
||||
CheckPreconditionsForPatching(isolate_, code_object);
|
||||
DCHECK(self_reference->IsOddball());
|
||||
DCHECK(Oddball::cast(*self_reference).kind() ==
|
||||
Oddball::kSelfReferenceMarker);
|
||||
#endif
|
||||
|
||||
uint32_t key;
|
||||
if (map_.Delete(self_reference, &key)) {
|
||||
@ -83,6 +89,17 @@ void BuiltinsConstantsTableBuilder::PatchSelfReference(
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinsConstantsTableBuilder::PatchBasicBlockCountersReference(
|
||||
Handle<ByteArray> counters) {
|
||||
CheckPreconditionsForPatching(isolate_, counters);
|
||||
|
||||
uint32_t key;
|
||||
if (map_.Delete(ReadOnlyRoots(isolate_).basic_block_counters_marker(),
|
||||
&key)) {
|
||||
map_.Set(counters, key);
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinsConstantsTableBuilder::Finalize() {
|
||||
HandleScope handle_scope(isolate_);
|
||||
|
||||
@ -117,6 +134,8 @@ void BuiltinsConstantsTableBuilder::Finalize() {
|
||||
DCHECK(table->get(i).IsHeapObject());
|
||||
DCHECK_NE(ReadOnlyRoots(isolate_).undefined_value(), table->get(i));
|
||||
DCHECK_NE(ReadOnlyRoots(isolate_).self_reference_marker(), table->get(i));
|
||||
DCHECK_NE(ReadOnlyRoots(isolate_).basic_block_counters_marker(),
|
||||
table->get(i));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -34,6 +34,11 @@ class BuiltinsConstantsTableBuilder final {
|
||||
void PatchSelfReference(Handle<Object> self_reference,
|
||||
Handle<Code> code_object);
|
||||
|
||||
// References to the array that stores basic block usage counters start out as
|
||||
// references to a unique oddball. Once the actual array has been allocated,
|
||||
// such entries in the constants map must be patched up.
|
||||
void PatchBasicBlockCountersReference(Handle<ByteArray> counters);
|
||||
|
||||
// Should be called after all affected code (e.g. builtins and bytecode
|
||||
// handlers) has been generated.
|
||||
void Finalize();
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "src/codegen/source-position-table.h"
|
||||
#include "src/codegen/tick-counter.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/diagnostics/basic-block-profiler.h"
|
||||
#include "src/execution/frames.h"
|
||||
#include "src/handles/handles.h"
|
||||
#include "src/objects/objects.h"
|
||||
@ -290,6 +291,11 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
|
||||
|
||||
TickCounter& tick_counter() { return tick_counter_; }
|
||||
|
||||
BasicBlockProfilerData* profiler_data() const { return profiler_data_; }
|
||||
void set_profiler_data(BasicBlockProfilerData* profiler_data) {
|
||||
profiler_data_ = profiler_data;
|
||||
}
|
||||
|
||||
private:
|
||||
OptimizedCompilationInfo(Code::Kind code_kind, Zone* zone);
|
||||
void ConfigureFlags();
|
||||
@ -318,6 +324,9 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
|
||||
// The compiled code.
|
||||
Handle<Code> code_;
|
||||
|
||||
// Basic block profiling support.
|
||||
BasicBlockProfilerData* profiler_data_ = nullptr;
|
||||
|
||||
// The WebAssembly compilation result, not published in the NativeModule yet.
|
||||
std::unique_ptr<wasm::WasmCompilationResult> wasm_compilation_result_;
|
||||
|
||||
|
@ -503,6 +503,7 @@ MaybeHandle<Code> CodeGenerator::FinalizeCode() {
|
||||
.set_deoptimization_data(deopt_data)
|
||||
.set_is_turbofanned()
|
||||
.set_stack_slots(frame()->GetTotalFrameSlotCount())
|
||||
.set_profiler_data(info()->profiler_data())
|
||||
.TryBuild();
|
||||
|
||||
Handle<Code> code;
|
||||
|
@ -37,16 +37,16 @@ static NodeVector::iterator FindInsertionPoint(BasicBlock* block) {
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
// TODO(dcarney): need to mark code as non-serializable.
|
||||
static const Operator* PointerConstant(CommonOperatorBuilder* common,
|
||||
intptr_t ptr) {
|
||||
const void* ptr) {
|
||||
intptr_t ptr_as_int = reinterpret_cast<intptr_t>(ptr);
|
||||
return kSystemPointerSize == 8
|
||||
? common->Int64Constant(ptr)
|
||||
: common->Int32Constant(static_cast<int32_t>(ptr));
|
||||
? common->Int64Constant(ptr_as_int)
|
||||
: common->Int32Constant(static_cast<int32_t>(ptr_as_int));
|
||||
}
|
||||
|
||||
BasicBlockProfiler::Data* BasicBlockInstrumentor::Instrument(
|
||||
BasicBlockProfilerData* BasicBlockInstrumentor::Instrument(
|
||||
OptimizedCompilationInfo* info, Graph* graph, Schedule* schedule,
|
||||
Isolate* isolate) {
|
||||
// Basic block profiling disables concurrent compilation, so handle deref is
|
||||
@ -54,41 +54,68 @@ BasicBlockProfiler::Data* BasicBlockInstrumentor::Instrument(
|
||||
AllowHandleDereference allow_handle_dereference;
|
||||
// Skip the exit block in profiles, since the register allocator can't handle
|
||||
// it and entry into it means falling off the end of the function anyway.
|
||||
size_t n_blocks = static_cast<size_t>(schedule->RpoBlockCount()) - 1;
|
||||
BasicBlockProfiler::Data* data = BasicBlockProfiler::Get()->NewData(n_blocks);
|
||||
size_t n_blocks = schedule->RpoBlockCount() - 1;
|
||||
BasicBlockProfilerData* data = BasicBlockProfiler::Get()->NewData(n_blocks);
|
||||
// Set the function name.
|
||||
data->SetFunctionName(info->GetDebugName());
|
||||
// Capture the schedule string before instrumentation.
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << *schedule;
|
||||
data->SetSchedule(&os);
|
||||
data->SetSchedule(os);
|
||||
}
|
||||
// Check whether we should write counts to a JS heap object or to the
|
||||
// BasicBlockProfilerData directly. The JS heap object is only used for
|
||||
// builtins.
|
||||
bool on_heap_counters = isolate && isolate->IsGeneratingEmbeddedBuiltins();
|
||||
// Add the increment instructions to the start of every block.
|
||||
CommonOperatorBuilder common(graph->zone());
|
||||
Node* zero = graph->NewNode(common.Int32Constant(0));
|
||||
Node* one = graph->NewNode(common.Int32Constant(1));
|
||||
MachineOperatorBuilder machine(graph->zone());
|
||||
Node* counters_array = nullptr;
|
||||
if (on_heap_counters) {
|
||||
// Allocation is disallowed here, so rather than referring to an actual
|
||||
// counters array, create a reference to a special marker object. This
|
||||
// object will get fixed up later in the constants table (see
|
||||
// PatchBasicBlockCountersReference). An important and subtle point: we
|
||||
// cannot use the root handle basic_block_counters_marker_handle() and must
|
||||
// create a new separate handle. Otherwise
|
||||
// TurboAssemblerBase::IndirectLoadConstant would helpfully emit a
|
||||
// root-relative load rather than putting this value in the constants table
|
||||
// where we expect it to be for patching.
|
||||
counters_array = graph->NewNode(common.HeapConstant(Handle<HeapObject>::New(
|
||||
ReadOnlyRoots(isolate).basic_block_counters_marker(), isolate)));
|
||||
} else {
|
||||
counters_array = graph->NewNode(PointerConstant(&common, data->counts()));
|
||||
}
|
||||
Node* one = graph->NewNode(common.Int32Constant(1));
|
||||
BasicBlockVector* blocks = schedule->rpo_order();
|
||||
size_t block_number = 0;
|
||||
for (BasicBlockVector::iterator it = blocks->begin(); block_number < n_blocks;
|
||||
++it, ++block_number) {
|
||||
BasicBlock* block = (*it);
|
||||
data->SetBlockRpoNumber(block_number, block->rpo_number());
|
||||
// TODO(dcarney): wire effect and control deps for load and store.
|
||||
// It is unnecessary to wire effect and control deps for load and store
|
||||
// since this happens after scheduling.
|
||||
// Construct increment operation.
|
||||
Node* base = graph->NewNode(
|
||||
PointerConstant(&common, data->GetCounterAddress(block_number)));
|
||||
Node* load = graph->NewNode(machine.Load(MachineType::Uint32()), base, zero,
|
||||
graph->start(), graph->start());
|
||||
int offset_to_counter_value = static_cast<int>(block_number) * kInt32Size;
|
||||
if (on_heap_counters) {
|
||||
offset_to_counter_value += ByteArray::kHeaderSize - kHeapObjectTag;
|
||||
}
|
||||
Node* offset_to_counter =
|
||||
graph->NewNode(common.Int32Constant(offset_to_counter_value));
|
||||
Node* load =
|
||||
graph->NewNode(machine.Load(MachineType::Uint32()), counters_array,
|
||||
offset_to_counter, graph->start(), graph->start());
|
||||
Node* inc = graph->NewNode(machine.Int32Add(), load, one);
|
||||
Node* store =
|
||||
graph->NewNode(machine.Store(StoreRepresentation(
|
||||
MachineRepresentation::kWord32, kNoWriteBarrier)),
|
||||
base, zero, inc, graph->start(), graph->start());
|
||||
Node* store = graph->NewNode(
|
||||
machine.Store(StoreRepresentation(MachineRepresentation::kWord32,
|
||||
kNoWriteBarrier)),
|
||||
counters_array, offset_to_counter, inc, graph->start(), graph->start());
|
||||
// Insert the new nodes.
|
||||
static const int kArraySize = 6;
|
||||
Node* to_insert[kArraySize] = {zero, one, base, load, inc, store};
|
||||
Node* to_insert[kArraySize] = {counters_array, one, offset_to_counter,
|
||||
load, inc, store};
|
||||
// The first two Nodes are constant across all blocks.
|
||||
int insertion_start = block_number == 0 ? 0 : 2;
|
||||
NodeVector::iterator insertion_point = FindInsertionPoint(block);
|
||||
block->InsertNodes(insertion_point, &to_insert[insertion_start],
|
||||
|
@ -20,9 +20,9 @@ class Schedule;
|
||||
|
||||
class BasicBlockInstrumentor : public AllStatic {
|
||||
public:
|
||||
static BasicBlockProfiler::Data* Instrument(OptimizedCompilationInfo* info,
|
||||
Graph* graph, Schedule* schedule,
|
||||
Isolate* isolate);
|
||||
static BasicBlockProfilerData* Instrument(OptimizedCompilationInfo* info,
|
||||
Graph* graph, Schedule* schedule,
|
||||
Isolate* isolate);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -349,11 +349,6 @@ class PipelineData {
|
||||
return register_allocation_data_;
|
||||
}
|
||||
|
||||
BasicBlockProfiler::Data* profiler_data() const { return profiler_data_; }
|
||||
void set_profiler_data(BasicBlockProfiler::Data* profiler_data) {
|
||||
profiler_data_ = profiler_data;
|
||||
}
|
||||
|
||||
std::string const& source_position_output() const {
|
||||
return source_position_output_;
|
||||
}
|
||||
@ -599,9 +594,6 @@ class PipelineData {
|
||||
Zone* register_allocation_zone_;
|
||||
RegisterAllocationData* register_allocation_data_ = nullptr;
|
||||
|
||||
// Basic block profiling support.
|
||||
BasicBlockProfiler::Data* profiler_data_ = nullptr;
|
||||
|
||||
// Source position output for --trace-turbo.
|
||||
std::string source_position_output_;
|
||||
|
||||
@ -2622,8 +2614,9 @@ MaybeHandle<Code> Pipeline::GenerateCodeForCodeStub(
|
||||
ZoneStats zone_stats(isolate->allocator());
|
||||
NodeOriginTable node_origins(graph);
|
||||
JumpOptimizationInfo jump_opt;
|
||||
bool should_optimize_jumps =
|
||||
isolate->serializer_enabled() && FLAG_turbo_rewrite_far_jumps;
|
||||
bool should_optimize_jumps = isolate->serializer_enabled() &&
|
||||
FLAG_turbo_rewrite_far_jumps &&
|
||||
!FLAG_turbo_profiling;
|
||||
PipelineData data(&zone_stats, &info, isolate, isolate->allocator(), graph,
|
||||
jsgraph, nullptr, source_positions, &node_origins,
|
||||
should_optimize_jumps ? &jump_opt : nullptr, options);
|
||||
@ -3055,7 +3048,7 @@ bool PipelineImpl::SelectInstructions(Linkage* linkage) {
|
||||
DCHECK_NOT_NULL(data->schedule());
|
||||
|
||||
if (FLAG_turbo_profiling) {
|
||||
data->set_profiler_data(BasicBlockInstrumentor::Instrument(
|
||||
data->info()->set_profiler_data(BasicBlockInstrumentor::Instrument(
|
||||
info(), data->graph(), data->schedule(), data->isolate()));
|
||||
}
|
||||
|
||||
@ -3273,14 +3266,6 @@ MaybeHandle<Code> PipelineImpl::FinalizeCode(bool retire_broker) {
|
||||
return maybe_code;
|
||||
}
|
||||
|
||||
if (data->profiler_data()) {
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
std::ostringstream os;
|
||||
code->Disassemble(nullptr, os, isolate());
|
||||
data->profiler_data()->SetCode(&os);
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
}
|
||||
|
||||
info()->SetCode(code);
|
||||
PrintCode(isolate(), code, info());
|
||||
|
||||
|
@ -2169,8 +2169,9 @@ void Shell::WriteLcovData(v8::Isolate* isolate, const char* file) {
|
||||
void Shell::OnExit(v8::Isolate* isolate) {
|
||||
// Dump basic block profiling data.
|
||||
if (i::FLAG_turbo_profiling) {
|
||||
i::BasicBlockProfiler* profiler = i::BasicBlockProfiler::Get();
|
||||
i::StdoutStream{} << *profiler;
|
||||
i::StdoutStream out;
|
||||
i::BasicBlockProfiler::Get()->Print(out,
|
||||
reinterpret_cast<i::Isolate*>(isolate));
|
||||
}
|
||||
isolate->Dispose();
|
||||
|
||||
|
@ -9,84 +9,132 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "src/base/lazy-instance.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "torque-generated/exported-class-definitions-tq-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
DEFINE_LAZY_LEAKY_OBJECT_GETTER(BasicBlockProfiler, BasicBlockProfiler::Get)
|
||||
|
||||
BasicBlockProfiler::Data::Data(size_t n_blocks)
|
||||
: n_blocks_(n_blocks),
|
||||
block_rpo_numbers_(n_blocks_),
|
||||
counts_(n_blocks_, 0) {}
|
||||
BasicBlockProfilerData::BasicBlockProfilerData(size_t n_blocks)
|
||||
: block_rpo_numbers_(n_blocks), counts_(n_blocks, 0) {}
|
||||
|
||||
static void InsertIntoString(std::ostringstream* os, std::string* string) {
|
||||
string->insert(0, os->str());
|
||||
void BasicBlockProfilerData::SetCode(const std::ostringstream& os) {
|
||||
code_ = os.str();
|
||||
}
|
||||
|
||||
static void InsertIntoString(const char* data, std::string* string) {
|
||||
string->insert(0, data);
|
||||
void BasicBlockProfilerData::SetFunctionName(std::unique_ptr<char[]> name) {
|
||||
function_name_ = name.get();
|
||||
}
|
||||
|
||||
void BasicBlockProfiler::Data::SetCode(std::ostringstream* os) {
|
||||
InsertIntoString(os, &code_);
|
||||
void BasicBlockProfilerData::SetSchedule(const std::ostringstream& os) {
|
||||
schedule_ = os.str();
|
||||
}
|
||||
|
||||
void BasicBlockProfiler::Data::SetFunctionName(std::unique_ptr<char[]> name) {
|
||||
InsertIntoString(name.get(), &function_name_);
|
||||
}
|
||||
|
||||
void BasicBlockProfiler::Data::SetSchedule(std::ostringstream* os) {
|
||||
InsertIntoString(os, &schedule_);
|
||||
}
|
||||
|
||||
void BasicBlockProfiler::Data::SetBlockRpoNumber(size_t offset,
|
||||
int32_t block_rpo) {
|
||||
DCHECK(offset < n_blocks_);
|
||||
void BasicBlockProfilerData::SetBlockRpoNumber(size_t offset,
|
||||
int32_t block_rpo) {
|
||||
DCHECK(offset < n_blocks());
|
||||
block_rpo_numbers_[offset] = block_rpo;
|
||||
}
|
||||
|
||||
intptr_t BasicBlockProfiler::Data::GetCounterAddress(size_t offset) {
|
||||
DCHECK(offset < n_blocks_);
|
||||
return reinterpret_cast<intptr_t>(&(counts_[offset]));
|
||||
}
|
||||
|
||||
void BasicBlockProfiler::Data::ResetCounts() {
|
||||
for (size_t i = 0; i < n_blocks_; ++i) {
|
||||
void BasicBlockProfilerData::ResetCounts() {
|
||||
for (size_t i = 0; i < n_blocks(); ++i) {
|
||||
counts_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
BasicBlockProfiler::Data* BasicBlockProfiler::NewData(size_t n_blocks) {
|
||||
BasicBlockProfilerData* BasicBlockProfiler::NewData(size_t n_blocks) {
|
||||
base::MutexGuard lock(&data_list_mutex_);
|
||||
Data* data = new Data(n_blocks);
|
||||
data_list_.push_back(data);
|
||||
return data;
|
||||
auto data = std::make_unique<BasicBlockProfilerData>(n_blocks);
|
||||
BasicBlockProfilerData* data_ptr = data.get();
|
||||
data_list_.push_back(std::move(data));
|
||||
return data_ptr;
|
||||
}
|
||||
|
||||
BasicBlockProfiler::~BasicBlockProfiler() {
|
||||
for (DataList::iterator i = data_list_.begin(); i != data_list_.end(); ++i) {
|
||||
delete (*i);
|
||||
namespace {
|
||||
Handle<String> CopyStringToJSHeap(const std::string& source, Isolate* isolate) {
|
||||
return isolate->factory()->NewStringFromAsciiChecked(source.c_str(),
|
||||
AllocationType::kOld);
|
||||
}
|
||||
|
||||
// Size of entries in both block_rpo_numbers and counts.
|
||||
constexpr int kBasicBlockSlotSize = kInt32Size;
|
||||
} // namespace
|
||||
|
||||
BasicBlockProfilerData::BasicBlockProfilerData(
|
||||
Handle<OnHeapBasicBlockProfilerData> js_heap_data, Isolate* isolate) {
|
||||
function_name_ = js_heap_data->name().ToCString().get();
|
||||
schedule_ = js_heap_data->schedule().ToCString().get();
|
||||
code_ = js_heap_data->code().ToCString().get();
|
||||
Handle<ByteArray> counts(js_heap_data->counts(), isolate);
|
||||
for (int i = 0; i < counts->length() / kBasicBlockSlotSize; ++i) {
|
||||
counts_.push_back(counts->get_uint32(i));
|
||||
}
|
||||
Handle<ByteArray> rpo_numbers(js_heap_data->block_rpo_numbers(), isolate);
|
||||
for (int i = 0; i < rpo_numbers->length() / kBasicBlockSlotSize; ++i) {
|
||||
block_rpo_numbers_.push_back(rpo_numbers->get_int(i));
|
||||
}
|
||||
CHECK_EQ(block_rpo_numbers_.size(), counts_.size());
|
||||
}
|
||||
|
||||
Handle<OnHeapBasicBlockProfilerData> BasicBlockProfilerData::CopyToJSHeap(
|
||||
Isolate* isolate) {
|
||||
int array_size_in_bytes = static_cast<int>(n_blocks() * kBasicBlockSlotSize);
|
||||
CHECK(array_size_in_bytes >= 0 &&
|
||||
static_cast<size_t>(array_size_in_bytes) / kBasicBlockSlotSize ==
|
||||
n_blocks()); // Overflow
|
||||
Handle<ByteArray> block_rpo_numbers = isolate->factory()->NewByteArray(
|
||||
array_size_in_bytes, AllocationType::kOld);
|
||||
for (int i = 0; i < static_cast<int>(n_blocks()); ++i) {
|
||||
block_rpo_numbers->set_int(i, block_rpo_numbers_[i]);
|
||||
}
|
||||
Handle<ByteArray> counts = isolate->factory()->NewByteArray(
|
||||
array_size_in_bytes, AllocationType::kOld);
|
||||
for (int i = 0; i < static_cast<int>(n_blocks()); ++i) {
|
||||
counts->set_uint32(i, counts_[i]);
|
||||
}
|
||||
Handle<String> name = CopyStringToJSHeap(function_name_, isolate);
|
||||
Handle<String> schedule = CopyStringToJSHeap(schedule_, isolate);
|
||||
Handle<String> code = CopyStringToJSHeap(code_, isolate);
|
||||
|
||||
return isolate->factory()->NewOnHeapBasicBlockProfilerData(
|
||||
block_rpo_numbers, counts, name, schedule, code, AllocationType::kOld);
|
||||
}
|
||||
|
||||
void BasicBlockProfiler::ResetCounts(Isolate* isolate) {
|
||||
for (const auto& data : data_list_) {
|
||||
data->ResetCounts();
|
||||
}
|
||||
Handle<ArrayList> list(isolate->heap()->basic_block_profiling_data(),
|
||||
isolate);
|
||||
for (int i = 0; i < list->Length(); ++i) {
|
||||
Handle<ByteArray> counts(
|
||||
OnHeapBasicBlockProfilerData::cast(list->Get(i)).counts(), isolate);
|
||||
for (int j = 0; j < counts->length() / kBasicBlockSlotSize; ++j) {
|
||||
counts->set_uint32(j, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BasicBlockProfiler::ResetCounts() {
|
||||
for (DataList::iterator i = data_list_.begin(); i != data_list_.end(); ++i) {
|
||||
(*i)->ResetCounts();
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const BasicBlockProfiler& p) {
|
||||
void BasicBlockProfiler::Print(std::ostream& os, Isolate* isolate) {
|
||||
os << "---- Start Profiling Data ----" << std::endl;
|
||||
using iterator = BasicBlockProfiler::DataList::const_iterator;
|
||||
for (iterator i = p.data_list_.begin(); i != p.data_list_.end(); ++i) {
|
||||
os << **i;
|
||||
for (const auto& data : data_list_) {
|
||||
os << *data;
|
||||
}
|
||||
HandleScope scope(isolate);
|
||||
Handle<ArrayList> list(isolate->heap()->basic_block_profiling_data(),
|
||||
isolate);
|
||||
for (int i = 0; i < list->Length(); ++i) {
|
||||
BasicBlockProfilerData data(
|
||||
handle(OnHeapBasicBlockProfilerData::cast(list->Get(i)), isolate),
|
||||
isolate);
|
||||
os << data;
|
||||
}
|
||||
os << "---- End Profiling Data ----" << std::endl;
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const BasicBlockProfiler::Data& d) {
|
||||
std::ostream& operator<<(std::ostream& os, const BasicBlockProfilerData& d) {
|
||||
int block_count_sum = std::accumulate(d.counts_.begin(), d.counts_.end(), 0);
|
||||
if (block_count_sum == 0) return os;
|
||||
const char* name = "unknown function";
|
||||
@ -100,8 +148,8 @@ std::ostream& operator<<(std::ostream& os, const BasicBlockProfiler::Data& d) {
|
||||
}
|
||||
os << "block counts for " << name << ":" << std::endl;
|
||||
std::vector<std::pair<int32_t, uint32_t>> pairs;
|
||||
pairs.reserve(d.n_blocks_);
|
||||
for (size_t i = 0; i < d.n_blocks_; ++i) {
|
||||
pairs.reserve(d.n_blocks());
|
||||
for (size_t i = 0; i < d.n_blocks(); ++i) {
|
||||
pairs.push_back(std::make_pair(d.block_rpo_numbers_[i], d.counts_[i]));
|
||||
}
|
||||
std::sort(pairs.begin(), pairs.end(),
|
||||
|
@ -14,66 +14,70 @@
|
||||
#include "src/base/macros.h"
|
||||
#include "src/base/platform/mutex.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "torque-generated/exported-class-definitions-tq.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class BasicBlockProfilerData {
|
||||
public:
|
||||
explicit BasicBlockProfilerData(size_t n_blocks);
|
||||
V8_EXPORT_PRIVATE BasicBlockProfilerData(
|
||||
Handle<OnHeapBasicBlockProfilerData> js_heap_data, Isolate* isolate);
|
||||
|
||||
size_t n_blocks() const {
|
||||
DCHECK_EQ(block_rpo_numbers_.size(), counts_.size());
|
||||
return block_rpo_numbers_.size();
|
||||
}
|
||||
const uint32_t* counts() const { return &counts_[0]; }
|
||||
|
||||
void SetCode(const std::ostringstream& os);
|
||||
void SetFunctionName(std::unique_ptr<char[]> name);
|
||||
void SetSchedule(const std::ostringstream& os);
|
||||
void SetBlockRpoNumber(size_t offset, int32_t block_rpo);
|
||||
|
||||
// Copy the data from this object into an equivalent object stored on the JS
|
||||
// heap, so that it can survive snapshotting and relocation. This must
|
||||
// happen on the main thread during finalization of the compilation.
|
||||
Handle<OnHeapBasicBlockProfilerData> CopyToJSHeap(Isolate* isolate);
|
||||
|
||||
private:
|
||||
friend class BasicBlockProfiler;
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
const BasicBlockProfilerData& s);
|
||||
|
||||
V8_EXPORT_PRIVATE void ResetCounts();
|
||||
|
||||
std::vector<int32_t> block_rpo_numbers_;
|
||||
std::vector<uint32_t> counts_;
|
||||
std::string function_name_;
|
||||
std::string schedule_;
|
||||
std::string code_;
|
||||
DISALLOW_COPY_AND_ASSIGN(BasicBlockProfilerData);
|
||||
};
|
||||
|
||||
class BasicBlockProfiler {
|
||||
public:
|
||||
class Data {
|
||||
public:
|
||||
size_t n_blocks() const { return n_blocks_; }
|
||||
const uint32_t* counts() const { return &counts_[0]; }
|
||||
|
||||
void SetCode(std::ostringstream* os);
|
||||
void SetFunctionName(std::unique_ptr<char[]> name);
|
||||
void SetSchedule(std::ostringstream* os);
|
||||
void SetBlockRpoNumber(size_t offset, int32_t block_rpo);
|
||||
intptr_t GetCounterAddress(size_t offset);
|
||||
|
||||
private:
|
||||
friend class BasicBlockProfiler;
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
const BasicBlockProfiler::Data& s);
|
||||
|
||||
explicit Data(size_t n_blocks);
|
||||
~Data() = default;
|
||||
|
||||
V8_EXPORT_PRIVATE void ResetCounts();
|
||||
|
||||
const size_t n_blocks_;
|
||||
std::vector<int32_t> block_rpo_numbers_;
|
||||
std::vector<uint32_t> counts_;
|
||||
std::string function_name_;
|
||||
std::string schedule_;
|
||||
std::string code_;
|
||||
DISALLOW_COPY_AND_ASSIGN(Data);
|
||||
};
|
||||
|
||||
using DataList = std::list<Data*>;
|
||||
using DataList = std::list<std::unique_ptr<BasicBlockProfilerData>>;
|
||||
|
||||
BasicBlockProfiler() = default;
|
||||
~BasicBlockProfiler();
|
||||
~BasicBlockProfiler() = default;
|
||||
|
||||
V8_EXPORT_PRIVATE static BasicBlockProfiler* Get();
|
||||
Data* NewData(size_t n_blocks);
|
||||
V8_EXPORT_PRIVATE void ResetCounts();
|
||||
BasicBlockProfilerData* NewData(size_t n_blocks);
|
||||
V8_EXPORT_PRIVATE void ResetCounts(Isolate* isolate);
|
||||
V8_EXPORT_PRIVATE void Print(std::ostream& os, Isolate* isolate);
|
||||
|
||||
const DataList* data_list() { return &data_list_; }
|
||||
|
||||
private:
|
||||
friend V8_EXPORT_PRIVATE std::ostream& operator<<(
|
||||
std::ostream& os, const BasicBlockProfiler& s);
|
||||
|
||||
DataList data_list_;
|
||||
base::Mutex data_list_mutex_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BasicBlockProfiler);
|
||||
};
|
||||
|
||||
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
|
||||
const BasicBlockProfiler& s);
|
||||
std::ostream& operator<<(std::ostream& os, const BasicBlockProfiler::Data& s);
|
||||
std::ostream& operator<<(std::ostream& os, const BasicBlockProfilerData& s);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -926,6 +926,8 @@ void Oddball::OddballVerify(Isolate* isolate) {
|
||||
} else if (map() == roots.self_reference_marker_map()) {
|
||||
// Multiple instances of this oddball may exist at once.
|
||||
CHECK_EQ(kind(), Oddball::kSelfReferenceMarker);
|
||||
} else if (map() == roots.basic_block_counters_marker_map()) {
|
||||
CHECK(*this == roots.basic_block_counters_marker());
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "src/builtins/constants-table-builder.h"
|
||||
#include "src/codegen/compiler.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/diagnostics/basic-block-profiler.h"
|
||||
#include "src/execution/isolate-inl.h"
|
||||
#include "src/execution/protectors-inl.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
@ -118,6 +119,22 @@ MaybeHandle<Code> Factory::CodeBuilder::BuildInternal(
|
||||
data_container->set_kind_specific_flags(kind_specific_flags_);
|
||||
}
|
||||
|
||||
// Basic block profiling data for builtins is stored in the JS heap rather
|
||||
// than in separately-allocated C++ objects. Allocate that data now if
|
||||
// appropriate.
|
||||
Handle<OnHeapBasicBlockProfilerData> on_heap_profiler_data;
|
||||
if (profiler_data_ && isolate_->IsGeneratingEmbeddedBuiltins()) {
|
||||
on_heap_profiler_data = profiler_data_->CopyToJSHeap(isolate_);
|
||||
|
||||
// Add the on-heap data to a global list, which keeps it alive and allows
|
||||
// iteration.
|
||||
Handle<ArrayList> list(isolate_->heap()->basic_block_profiling_data(),
|
||||
isolate_);
|
||||
Handle<ArrayList> new_list =
|
||||
ArrayList::Add(isolate_, list, on_heap_profiler_data);
|
||||
isolate_->heap()->SetBasicBlockProfilingData(new_list);
|
||||
}
|
||||
|
||||
Handle<Code> code;
|
||||
{
|
||||
int object_size = ComputeCodeObjectSize(code_desc_);
|
||||
@ -189,6 +206,14 @@ MaybeHandle<Code> Factory::CodeBuilder::BuildInternal(
|
||||
*(self_reference.location()) = code->ptr();
|
||||
}
|
||||
|
||||
// Likewise, any references to the basic block counters marker need to be
|
||||
// updated to point to the newly-allocated counters array.
|
||||
if (!on_heap_profiler_data.is_null()) {
|
||||
isolate_->builtins_constants_table_builder()
|
||||
->PatchBasicBlockCountersReference(
|
||||
handle(on_heap_profiler_data->counts(), isolate_));
|
||||
}
|
||||
|
||||
// Migrate generated code.
|
||||
// The generated code can contain embedded objects (typically from handles)
|
||||
// in a pointer-to-tagged-value format (i.e. with indirection like a handle)
|
||||
@ -211,6 +236,21 @@ MaybeHandle<Code> Factory::CodeBuilder::BuildInternal(
|
||||
code->FlushICache();
|
||||
}
|
||||
|
||||
if (profiler_data_) {
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
std::ostringstream os;
|
||||
code->Disassemble(nullptr, os, isolate_);
|
||||
if (!on_heap_profiler_data.is_null()) {
|
||||
Handle<String> disassembly =
|
||||
isolate_->factory()->NewStringFromAsciiChecked(os.str().c_str(),
|
||||
AllocationType::kOld);
|
||||
on_heap_profiler_data->set_code(*disassembly);
|
||||
} else {
|
||||
profiler_data_->SetCode(os);
|
||||
}
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
@ -325,6 +365,13 @@ Handle<Oddball> Factory::NewSelfReferenceMarker() {
|
||||
Oddball::kSelfReferenceMarker);
|
||||
}
|
||||
|
||||
Handle<Oddball> Factory::NewBasicBlockCountersMarker() {
|
||||
return NewOddball(basic_block_counters_marker_map(),
|
||||
"basic_block_counters_marker",
|
||||
handle(Smi::FromInt(-1), isolate()), "undefined",
|
||||
Oddball::kBasicBlockCountersMarker);
|
||||
}
|
||||
|
||||
Handle<PropertyArray> Factory::NewPropertyArray(int length) {
|
||||
DCHECK_LE(0, length);
|
||||
if (length == 0) return empty_property_array();
|
||||
|
@ -26,6 +26,7 @@ namespace internal {
|
||||
// Forward declarations.
|
||||
class AliasedArgumentsEntry;
|
||||
class ObjectBoilerplateDescription;
|
||||
class BasicBlockProfilerData;
|
||||
class BreakPoint;
|
||||
class BreakPointInfo;
|
||||
class CallableTask;
|
||||
@ -119,6 +120,10 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
// Marks self references within code generation.
|
||||
Handle<Oddball> NewSelfReferenceMarker();
|
||||
|
||||
// Marks references to a function's basic-block usage counters array during
|
||||
// code generation.
|
||||
Handle<Oddball> NewBasicBlockCountersMarker();
|
||||
|
||||
// Allocates a property array initialized with undefined values.
|
||||
Handle<PropertyArray> NewPropertyArray(int length);
|
||||
// Tries allocating a fixed array initialized with undefined values.
|
||||
@ -861,6 +866,11 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
return *this;
|
||||
}
|
||||
|
||||
CodeBuilder& set_profiler_data(BasicBlockProfilerData* profiler_data) {
|
||||
profiler_data_ = profiler_data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
MaybeHandle<Code> BuildInternal(bool retry_allocation_or_fail);
|
||||
|
||||
@ -875,6 +885,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
Handle<ByteArray> source_position_table_;
|
||||
Handle<DeoptimizationData> deoptimization_data_ =
|
||||
DeoptimizationData::Empty(isolate_);
|
||||
BasicBlockProfilerData* profiler_data_ = nullptr;
|
||||
bool is_executable_ = true;
|
||||
bool read_only_data_container_ = false;
|
||||
bool is_movable_ = true;
|
||||
|
@ -176,6 +176,10 @@ void Heap::SetSerializedGlobalProxySizes(FixedArray sizes) {
|
||||
set_serialized_global_proxy_sizes(sizes);
|
||||
}
|
||||
|
||||
void Heap::SetBasicBlockProfilingData(Handle<ArrayList> list) {
|
||||
set_basic_block_profiling_data(*list);
|
||||
}
|
||||
|
||||
bool Heap::GCCallbackTuple::operator==(
|
||||
const Heap::GCCallbackTuple& other) const {
|
||||
return other.callback == callback && other.data == data;
|
||||
|
@ -663,6 +663,8 @@ class Heap {
|
||||
void SetSerializedObjects(FixedArray objects);
|
||||
void SetSerializedGlobalProxySizes(FixedArray sizes);
|
||||
|
||||
void SetBasicBlockProfilingData(Handle<ArrayList> list);
|
||||
|
||||
// For post mortem debugging.
|
||||
void RememberUnmappedPage(Address page, bool compacted);
|
||||
|
||||
|
@ -393,6 +393,7 @@ bool Heap::CreateInitialMaps() {
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, optimized_out);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, stale_register);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, self_reference_marker);
|
||||
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, basic_block_counters_marker);
|
||||
ALLOCATE_VARSIZE_MAP(BIGINT_TYPE, bigint);
|
||||
|
||||
for (unsigned i = 0; i < arraysize(string_type_table); i++) {
|
||||
@ -717,8 +718,9 @@ void Heap::CreateInitialObjects() {
|
||||
handle(Smi::FromInt(-7), isolate()), "undefined",
|
||||
Oddball::kStaleRegister));
|
||||
|
||||
// Initialize the self-reference marker.
|
||||
// Initialize marker objects used during compilation.
|
||||
set_self_reference_marker(*factory->NewSelfReferenceMarker());
|
||||
set_basic_block_counters_marker(*factory->NewBasicBlockCountersMarker());
|
||||
|
||||
set_interpreter_entry_trampoline_for_profiling(roots.undefined_value());
|
||||
|
||||
@ -769,6 +771,8 @@ void Heap::CreateInitialObjects() {
|
||||
set_number_string_cache(*factory->NewFixedArray(
|
||||
kInitialNumberStringCacheSize * 2, AllocationType::kOld));
|
||||
|
||||
set_basic_block_profiling_data(ArrayList::cast(roots.empty_fixed_array()));
|
||||
|
||||
// Allocate cache for string split and regexp-multiple.
|
||||
set_string_split_cache(*factory->NewFixedArray(
|
||||
RegExpResultsCache::kRegExpResultsCacheSize, AllocationType::kOld));
|
||||
|
@ -47,6 +47,7 @@ class Oddball : public TorqueGeneratedOddball<Oddball, PrimitiveHeapObject> {
|
||||
static const byte kOptimizedOut = 9;
|
||||
static const byte kStaleRegister = 10;
|
||||
static const byte kSelfReferenceMarker = 10;
|
||||
static const byte kBasicBlockCountersMarker = 11;
|
||||
|
||||
static_assert(kStartOfWeakFieldsOffset == kEndOfWeakFieldsOffset,
|
||||
"Ensure BodyDescriptor does not need to handle weak fields.");
|
||||
|
@ -77,3 +77,12 @@ extern class UncompiledDataWithoutPreparseData extends UncompiledData {
|
||||
extern class UncompiledDataWithPreparseData extends UncompiledData {
|
||||
preparse_data: PreparseData;
|
||||
}
|
||||
|
||||
@export
|
||||
class OnHeapBasicBlockProfilerData extends HeapObject {
|
||||
block_rpo_numbers: ByteArray; // Stored as 4-byte ints
|
||||
counts: ByteArray; // Stored as 4-byte ints
|
||||
name: String;
|
||||
schedule: String;
|
||||
code: String;
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ class Symbol;
|
||||
V(Map, optimized_out_map, OptimizedOutMap) \
|
||||
V(Map, stale_register_map, StaleRegisterMap) \
|
||||
V(Map, self_reference_marker_map, SelfReferenceMarkerMap) \
|
||||
V(Map, basic_block_counters_marker_map, BasicBlockCountersMarkerMap) \
|
||||
/* Canonical empty values */ \
|
||||
V(EnumCache, empty_enum_cache, EmptyEnumCache) \
|
||||
V(PropertyArray, empty_property_array, EmptyPropertyArray) \
|
||||
@ -185,6 +186,8 @@ class Symbol;
|
||||
V(HeapNumber, minus_infinity_value, MinusInfinityValue) \
|
||||
/* Marker for self-references during code-generation */ \
|
||||
V(HeapObject, self_reference_marker, SelfReferenceMarker) \
|
||||
/* Marker for basic-block usage counters array during code-generation */ \
|
||||
V(Oddball, basic_block_counters_marker, BasicBlockCountersMarker) \
|
||||
/* Canonical off-heap trampoline data */ \
|
||||
V(ByteArray, off_heap_trampoline_relocation_info, \
|
||||
OffHeapTrampolineRelocationInfo) \
|
||||
@ -303,6 +306,7 @@ class Symbol;
|
||||
InterpreterEntryTrampolineForProfiling) \
|
||||
V(Object, pending_optimize_for_test_bytecode, \
|
||||
PendingOptimizeForTestBytecode) \
|
||||
V(ArrayList, basic_block_profiling_data, BasicBlockProfilingData) \
|
||||
V(WeakArrayList, shared_wasm_memories, SharedWasmMemories)
|
||||
|
||||
// Entries in this list are limited to Smis and are not visited during GC.
|
||||
|
@ -18,13 +18,15 @@ class BasicBlockProfilerTest : public RawMachineAssemblerTester<int32_t> {
|
||||
FLAG_turbo_profiling = true;
|
||||
}
|
||||
|
||||
void ResetCounts() { BasicBlockProfiler::Get()->ResetCounts(); }
|
||||
void ResetCounts() {
|
||||
BasicBlockProfiler::Get()->ResetCounts(CcTest::i_isolate());
|
||||
}
|
||||
|
||||
void Expect(size_t size, uint32_t* expected) {
|
||||
const BasicBlockProfiler::DataList* l =
|
||||
BasicBlockProfiler::Get()->data_list();
|
||||
CHECK_NE(0, static_cast<int>(l->size()));
|
||||
const BasicBlockProfiler::Data* data = l->back();
|
||||
const BasicBlockProfilerData* data = l->back().get();
|
||||
CHECK_EQ(static_cast<int>(size), static_cast<int>(data->n_blocks()));
|
||||
const uint32_t* counts = data->counts();
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
|
@ -42,6 +42,7 @@ bool IsInitiallyMutable(Factory* factory, Address object_address) {
|
||||
#define INITIALLY_READ_ONLY_ROOT_LIST(V) \
|
||||
V(api_private_symbol_table) \
|
||||
V(api_symbol_table) \
|
||||
V(basic_block_profiling_data) \
|
||||
V(builtins_constants_table) \
|
||||
V(current_microtask) \
|
||||
V(detached_contexts) \
|
||||
|
@ -131,22 +131,23 @@ INSTANCE_TYPES = {
|
||||
167: "INTERNAL_CLASS_TYPE",
|
||||
168: "INTERNAL_CLASS_WITH_STRUCT_ELEMENTS_TYPE",
|
||||
169: "MAP_TYPE",
|
||||
170: "PREPARSE_DATA_TYPE",
|
||||
171: "PROPERTY_ARRAY_TYPE",
|
||||
172: "PROPERTY_CELL_TYPE",
|
||||
173: "SHARED_FUNCTION_INFO_TYPE",
|
||||
174: "SMI_BOX_TYPE",
|
||||
175: "SMI_PAIR_TYPE",
|
||||
176: "SORT_STATE_TYPE",
|
||||
177: "WASM_ARRAY_TYPE",
|
||||
178: "WASM_STRUCT_TYPE",
|
||||
179: "WEAK_ARRAY_LIST_TYPE",
|
||||
180: "WEAK_CELL_TYPE",
|
||||
181: "JS_PROXY_TYPE",
|
||||
170: "ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE",
|
||||
171: "PREPARSE_DATA_TYPE",
|
||||
172: "PROPERTY_ARRAY_TYPE",
|
||||
173: "PROPERTY_CELL_TYPE",
|
||||
174: "SHARED_FUNCTION_INFO_TYPE",
|
||||
175: "SMI_BOX_TYPE",
|
||||
176: "SMI_PAIR_TYPE",
|
||||
177: "SORT_STATE_TYPE",
|
||||
178: "WASM_ARRAY_TYPE",
|
||||
179: "WASM_STRUCT_TYPE",
|
||||
180: "WEAK_ARRAY_LIST_TYPE",
|
||||
181: "WEAK_CELL_TYPE",
|
||||
182: "JS_PROXY_TYPE",
|
||||
1057: "JS_OBJECT_TYPE",
|
||||
182: "JS_GLOBAL_OBJECT_TYPE",
|
||||
183: "JS_GLOBAL_PROXY_TYPE",
|
||||
184: "JS_MODULE_NAMESPACE_TYPE",
|
||||
183: "JS_GLOBAL_OBJECT_TYPE",
|
||||
184: "JS_GLOBAL_PROXY_TYPE",
|
||||
185: "JS_MODULE_NAMESPACE_TYPE",
|
||||
1040: "JS_SPECIAL_API_OBJECT_TYPE",
|
||||
1041: "JS_PRIMITIVE_WRAPPER_TYPE",
|
||||
1042: "JS_MAP_KEY_ITERATOR_TYPE",
|
||||
@ -223,10 +224,10 @@ KNOWN_MAPS = {
|
||||
("read_only_space", 0x00529): (64, "SymbolMap"),
|
||||
("read_only_space", 0x00551): (40, "OneByteStringMap"),
|
||||
("read_only_space", 0x00579): (130, "ScopeInfoMap"),
|
||||
("read_only_space", 0x005a1): (173, "SharedFunctionInfoMap"),
|
||||
("read_only_space", 0x005a1): (174, "SharedFunctionInfoMap"),
|
||||
("read_only_space", 0x005c9): (158, "CodeMap"),
|
||||
("read_only_space", 0x005f1): (157, "CellMap"),
|
||||
("read_only_space", 0x00619): (172, "GlobalPropertyCellMap"),
|
||||
("read_only_space", 0x00619): (173, "GlobalPropertyCellMap"),
|
||||
("read_only_space", 0x00641): (70, "ForeignMap"),
|
||||
("read_only_space", 0x00669): (156, "TransitionArrayMap"),
|
||||
("read_only_space", 0x00691): (45, "ThinOneByteStringMap"),
|
||||
@ -256,8 +257,8 @@ KNOWN_MAPS = {
|
||||
("read_only_space", 0x00b7d): (123, "OrderedHashMapMap"),
|
||||
("read_only_space", 0x00ba5): (124, "OrderedHashSetMap"),
|
||||
("read_only_space", 0x00bcd): (125, "OrderedNameDictionaryMap"),
|
||||
("read_only_space", 0x00bf5): (170, "PreparseDataMap"),
|
||||
("read_only_space", 0x00c1d): (171, "PropertyArrayMap"),
|
||||
("read_only_space", 0x00bf5): (171, "PreparseDataMap"),
|
||||
("read_only_space", 0x00c1d): (172, "PropertyArrayMap"),
|
||||
("read_only_space", 0x00c45): (92, "SideEffectCallHandlerInfoMap"),
|
||||
("read_only_space", 0x00c6d): (92, "SideEffectFreeCallHandlerInfoMap"),
|
||||
("read_only_space", 0x00c95): (92, "NextCallSideEffectFreeCallHandlerInfoMap"),
|
||||
@ -271,10 +272,10 @@ KNOWN_MAPS = {
|
||||
("read_only_space", 0x00dd5): (152, "SyntheticModuleMap"),
|
||||
("read_only_space", 0x00dfd): (154, "UncompiledDataWithoutPreparseDataMap"),
|
||||
("read_only_space", 0x00e25): (153, "UncompiledDataWithPreparseDataMap"),
|
||||
("read_only_space", 0x00e4d): (179, "WeakArrayListMap"),
|
||||
("read_only_space", 0x00e4d): (180, "WeakArrayListMap"),
|
||||
("read_only_space", 0x00e75): (119, "EphemeronHashTableMap"),
|
||||
("read_only_space", 0x00e9d): (162, "EmbedderDataArrayMap"),
|
||||
("read_only_space", 0x00ec5): (180, "WeakCellMap"),
|
||||
("read_only_space", 0x00ec5): (181, "WeakCellMap"),
|
||||
("read_only_space", 0x00eed): (32, "StringMap"),
|
||||
("read_only_space", 0x00f15): (41, "ConsOneByteStringMap"),
|
||||
("read_only_space", 0x00f3d): (33, "ConsStringMap"),
|
||||
@ -291,66 +292,68 @@ KNOWN_MAPS = {
|
||||
("read_only_space", 0x010f5): (26, "UncachedExternalOneByteInternalizedStringMap"),
|
||||
("read_only_space", 0x0111d): (58, "UncachedExternalOneByteStringMap"),
|
||||
("read_only_space", 0x01145): (67, "SelfReferenceMarkerMap"),
|
||||
("read_only_space", 0x01179): (95, "EnumCacheMap"),
|
||||
("read_only_space", 0x011c9): (86, "ArrayBoilerplateDescriptionMap"),
|
||||
("read_only_space", 0x012c5): (98, "InterceptorInfoMap"),
|
||||
("read_only_space", 0x03335): (71, "PromiseFulfillReactionJobTaskMap"),
|
||||
("read_only_space", 0x0335d): (72, "PromiseRejectReactionJobTaskMap"),
|
||||
("read_only_space", 0x03385): (73, "CallableTaskMap"),
|
||||
("read_only_space", 0x033ad): (74, "CallbackTaskMap"),
|
||||
("read_only_space", 0x033d5): (75, "PromiseResolveThenableJobTaskMap"),
|
||||
("read_only_space", 0x033fd): (78, "FunctionTemplateInfoMap"),
|
||||
("read_only_space", 0x03425): (79, "ObjectTemplateInfoMap"),
|
||||
("read_only_space", 0x0344d): (80, "AccessCheckInfoMap"),
|
||||
("read_only_space", 0x03475): (81, "AccessorInfoMap"),
|
||||
("read_only_space", 0x0349d): (82, "AccessorPairMap"),
|
||||
("read_only_space", 0x034c5): (83, "AliasedArgumentsEntryMap"),
|
||||
("read_only_space", 0x034ed): (84, "AllocationMementoMap"),
|
||||
("read_only_space", 0x03515): (87, "AsmWasmDataMap"),
|
||||
("read_only_space", 0x0353d): (88, "AsyncGeneratorRequestMap"),
|
||||
("read_only_space", 0x03565): (89, "BreakPointMap"),
|
||||
("read_only_space", 0x0358d): (90, "BreakPointInfoMap"),
|
||||
("read_only_space", 0x035b5): (91, "CachedTemplateObjectMap"),
|
||||
("read_only_space", 0x035dd): (93, "ClassPositionsMap"),
|
||||
("read_only_space", 0x03605): (94, "DebugInfoMap"),
|
||||
("read_only_space", 0x0362d): (97, "FunctionTemplateRareDataMap"),
|
||||
("read_only_space", 0x03655): (99, "InterpreterDataMap"),
|
||||
("read_only_space", 0x0367d): (100, "PromiseCapabilityMap"),
|
||||
("read_only_space", 0x036a5): (101, "PromiseReactionMap"),
|
||||
("read_only_space", 0x036cd): (102, "PropertyDescriptorObjectMap"),
|
||||
("read_only_space", 0x036f5): (103, "PrototypeInfoMap"),
|
||||
("read_only_space", 0x0371d): (104, "ScriptMap"),
|
||||
("read_only_space", 0x03745): (105, "SourceTextModuleInfoEntryMap"),
|
||||
("read_only_space", 0x0376d): (106, "StackFrameInfoMap"),
|
||||
("read_only_space", 0x03795): (107, "StackTraceFrameMap"),
|
||||
("read_only_space", 0x037bd): (108, "TemplateObjectDescriptionMap"),
|
||||
("read_only_space", 0x037e5): (109, "Tuple2Map"),
|
||||
("read_only_space", 0x0380d): (110, "WasmCapiFunctionDataMap"),
|
||||
("read_only_space", 0x03835): (111, "WasmDebugInfoMap"),
|
||||
("read_only_space", 0x0385d): (112, "WasmExceptionTagMap"),
|
||||
("read_only_space", 0x03885): (113, "WasmExportedFunctionDataMap"),
|
||||
("read_only_space", 0x038ad): (114, "WasmIndirectFunctionTableMap"),
|
||||
("read_only_space", 0x038d5): (115, "WasmJSFunctionDataMap"),
|
||||
("read_only_space", 0x038fd): (116, "WasmValueMap"),
|
||||
("read_only_space", 0x03925): (167, "InternalClassMap"),
|
||||
("read_only_space", 0x0394d): (175, "SmiPairMap"),
|
||||
("read_only_space", 0x03975): (174, "SmiBoxMap"),
|
||||
("read_only_space", 0x0399d): (149, "ExportedSubClassBaseMap"),
|
||||
("read_only_space", 0x039c5): (150, "ExportedSubClassMap"),
|
||||
("read_only_space", 0x039ed): (68, "AbstractInternalClassSubclass1Map"),
|
||||
("read_only_space", 0x03a15): (69, "AbstractInternalClassSubclass2Map"),
|
||||
("read_only_space", 0x03a3d): (135, "InternalClassWithSmiElementsMap"),
|
||||
("read_only_space", 0x03a65): (168, "InternalClassWithStructElementsMap"),
|
||||
("read_only_space", 0x03a8d): (176, "SortStateMap"),
|
||||
("read_only_space", 0x03ab5): (85, "AllocationSiteWithWeakNextMap"),
|
||||
("read_only_space", 0x03add): (85, "AllocationSiteWithoutWeakNextMap"),
|
||||
("read_only_space", 0x03b05): (76, "LoadHandler1Map"),
|
||||
("read_only_space", 0x03b2d): (76, "LoadHandler2Map"),
|
||||
("read_only_space", 0x03b55): (76, "LoadHandler3Map"),
|
||||
("read_only_space", 0x03b7d): (77, "StoreHandler0Map"),
|
||||
("read_only_space", 0x03ba5): (77, "StoreHandler1Map"),
|
||||
("read_only_space", 0x03bcd): (77, "StoreHandler2Map"),
|
||||
("read_only_space", 0x03bf5): (77, "StoreHandler3Map"),
|
||||
("read_only_space", 0x0116d): (67, "BasicBlockCountersMarkerMap"),
|
||||
("read_only_space", 0x011a1): (95, "EnumCacheMap"),
|
||||
("read_only_space", 0x011f1): (86, "ArrayBoilerplateDescriptionMap"),
|
||||
("read_only_space", 0x012ed): (98, "InterceptorInfoMap"),
|
||||
("read_only_space", 0x033a1): (71, "PromiseFulfillReactionJobTaskMap"),
|
||||
("read_only_space", 0x033c9): (72, "PromiseRejectReactionJobTaskMap"),
|
||||
("read_only_space", 0x033f1): (73, "CallableTaskMap"),
|
||||
("read_only_space", 0x03419): (74, "CallbackTaskMap"),
|
||||
("read_only_space", 0x03441): (75, "PromiseResolveThenableJobTaskMap"),
|
||||
("read_only_space", 0x03469): (78, "FunctionTemplateInfoMap"),
|
||||
("read_only_space", 0x03491): (79, "ObjectTemplateInfoMap"),
|
||||
("read_only_space", 0x034b9): (80, "AccessCheckInfoMap"),
|
||||
("read_only_space", 0x034e1): (81, "AccessorInfoMap"),
|
||||
("read_only_space", 0x03509): (82, "AccessorPairMap"),
|
||||
("read_only_space", 0x03531): (83, "AliasedArgumentsEntryMap"),
|
||||
("read_only_space", 0x03559): (84, "AllocationMementoMap"),
|
||||
("read_only_space", 0x03581): (87, "AsmWasmDataMap"),
|
||||
("read_only_space", 0x035a9): (88, "AsyncGeneratorRequestMap"),
|
||||
("read_only_space", 0x035d1): (89, "BreakPointMap"),
|
||||
("read_only_space", 0x035f9): (90, "BreakPointInfoMap"),
|
||||
("read_only_space", 0x03621): (91, "CachedTemplateObjectMap"),
|
||||
("read_only_space", 0x03649): (93, "ClassPositionsMap"),
|
||||
("read_only_space", 0x03671): (94, "DebugInfoMap"),
|
||||
("read_only_space", 0x03699): (97, "FunctionTemplateRareDataMap"),
|
||||
("read_only_space", 0x036c1): (99, "InterpreterDataMap"),
|
||||
("read_only_space", 0x036e9): (100, "PromiseCapabilityMap"),
|
||||
("read_only_space", 0x03711): (101, "PromiseReactionMap"),
|
||||
("read_only_space", 0x03739): (102, "PropertyDescriptorObjectMap"),
|
||||
("read_only_space", 0x03761): (103, "PrototypeInfoMap"),
|
||||
("read_only_space", 0x03789): (104, "ScriptMap"),
|
||||
("read_only_space", 0x037b1): (105, "SourceTextModuleInfoEntryMap"),
|
||||
("read_only_space", 0x037d9): (106, "StackFrameInfoMap"),
|
||||
("read_only_space", 0x03801): (107, "StackTraceFrameMap"),
|
||||
("read_only_space", 0x03829): (108, "TemplateObjectDescriptionMap"),
|
||||
("read_only_space", 0x03851): (109, "Tuple2Map"),
|
||||
("read_only_space", 0x03879): (110, "WasmCapiFunctionDataMap"),
|
||||
("read_only_space", 0x038a1): (111, "WasmDebugInfoMap"),
|
||||
("read_only_space", 0x038c9): (112, "WasmExceptionTagMap"),
|
||||
("read_only_space", 0x038f1): (113, "WasmExportedFunctionDataMap"),
|
||||
("read_only_space", 0x03919): (114, "WasmIndirectFunctionTableMap"),
|
||||
("read_only_space", 0x03941): (115, "WasmJSFunctionDataMap"),
|
||||
("read_only_space", 0x03969): (116, "WasmValueMap"),
|
||||
("read_only_space", 0x03991): (170, "OnHeapBasicBlockProfilerDataMap"),
|
||||
("read_only_space", 0x039b9): (167, "InternalClassMap"),
|
||||
("read_only_space", 0x039e1): (176, "SmiPairMap"),
|
||||
("read_only_space", 0x03a09): (175, "SmiBoxMap"),
|
||||
("read_only_space", 0x03a31): (149, "ExportedSubClassBaseMap"),
|
||||
("read_only_space", 0x03a59): (150, "ExportedSubClassMap"),
|
||||
("read_only_space", 0x03a81): (68, "AbstractInternalClassSubclass1Map"),
|
||||
("read_only_space", 0x03aa9): (69, "AbstractInternalClassSubclass2Map"),
|
||||
("read_only_space", 0x03ad1): (135, "InternalClassWithSmiElementsMap"),
|
||||
("read_only_space", 0x03af9): (168, "InternalClassWithStructElementsMap"),
|
||||
("read_only_space", 0x03b21): (177, "SortStateMap"),
|
||||
("read_only_space", 0x03b49): (85, "AllocationSiteWithWeakNextMap"),
|
||||
("read_only_space", 0x03b71): (85, "AllocationSiteWithoutWeakNextMap"),
|
||||
("read_only_space", 0x03b99): (76, "LoadHandler1Map"),
|
||||
("read_only_space", 0x03bc1): (76, "LoadHandler2Map"),
|
||||
("read_only_space", 0x03be9): (76, "LoadHandler3Map"),
|
||||
("read_only_space", 0x03c11): (77, "StoreHandler0Map"),
|
||||
("read_only_space", 0x03c39): (77, "StoreHandler1Map"),
|
||||
("read_only_space", 0x03c61): (77, "StoreHandler2Map"),
|
||||
("read_only_space", 0x03c89): (77, "StoreHandler3Map"),
|
||||
("map_space", 0x00121): (1057, "ExternalMap"),
|
||||
("map_space", 0x00149): (1073, "JSMessageObjectMap"),
|
||||
}
|
||||
@ -375,32 +378,33 @@ KNOWN_OBJECTS = {
|
||||
("read_only_space", 0x007ad): "TerminationException",
|
||||
("read_only_space", 0x00815): "OptimizedOut",
|
||||
("read_only_space", 0x00875): "StaleRegister",
|
||||
("read_only_space", 0x0116d): "EmptyEnumCache",
|
||||
("read_only_space", 0x011a1): "EmptyPropertyArray",
|
||||
("read_only_space", 0x011a9): "EmptyByteArray",
|
||||
("read_only_space", 0x011b1): "EmptyObjectBoilerplateDescription",
|
||||
("read_only_space", 0x011bd): "EmptyArrayBoilerplateDescription",
|
||||
("read_only_space", 0x011f1): "EmptyClosureFeedbackCellArray",
|
||||
("read_only_space", 0x011f9): "EmptySloppyArgumentsElements",
|
||||
("read_only_space", 0x01209): "EmptySlowElementDictionary",
|
||||
("read_only_space", 0x0122d): "EmptyOrderedHashMap",
|
||||
("read_only_space", 0x01241): "EmptyOrderedHashSet",
|
||||
("read_only_space", 0x01255): "EmptyFeedbackMetadata",
|
||||
("read_only_space", 0x01261): "EmptyPropertyCell",
|
||||
("read_only_space", 0x01275): "EmptyPropertyDictionary",
|
||||
("read_only_space", 0x0129d): "NoOpInterceptorInfo",
|
||||
("read_only_space", 0x012ed): "EmptyWeakArrayList",
|
||||
("read_only_space", 0x012f9): "InfinityValue",
|
||||
("read_only_space", 0x01305): "MinusZeroValue",
|
||||
("read_only_space", 0x01311): "MinusInfinityValue",
|
||||
("read_only_space", 0x0131d): "SelfReferenceMarker",
|
||||
("read_only_space", 0x0135d): "OffHeapTrampolineRelocationInfo",
|
||||
("read_only_space", 0x01369): "TrampolineTrivialCodeDataContainer",
|
||||
("read_only_space", 0x01375): "TrampolinePromiseRejectionCodeDataContainer",
|
||||
("read_only_space", 0x01381): "GlobalThisBindingScopeInfo",
|
||||
("read_only_space", 0x013b9): "EmptyFunctionScopeInfo",
|
||||
("read_only_space", 0x013e1): "NativeScopeInfo",
|
||||
("read_only_space", 0x013fd): "HashSeed",
|
||||
("read_only_space", 0x01195): "EmptyEnumCache",
|
||||
("read_only_space", 0x011c9): "EmptyPropertyArray",
|
||||
("read_only_space", 0x011d1): "EmptyByteArray",
|
||||
("read_only_space", 0x011d9): "EmptyObjectBoilerplateDescription",
|
||||
("read_only_space", 0x011e5): "EmptyArrayBoilerplateDescription",
|
||||
("read_only_space", 0x01219): "EmptyClosureFeedbackCellArray",
|
||||
("read_only_space", 0x01221): "EmptySloppyArgumentsElements",
|
||||
("read_only_space", 0x01231): "EmptySlowElementDictionary",
|
||||
("read_only_space", 0x01255): "EmptyOrderedHashMap",
|
||||
("read_only_space", 0x01269): "EmptyOrderedHashSet",
|
||||
("read_only_space", 0x0127d): "EmptyFeedbackMetadata",
|
||||
("read_only_space", 0x01289): "EmptyPropertyCell",
|
||||
("read_only_space", 0x0129d): "EmptyPropertyDictionary",
|
||||
("read_only_space", 0x012c5): "NoOpInterceptorInfo",
|
||||
("read_only_space", 0x01315): "EmptyWeakArrayList",
|
||||
("read_only_space", 0x01321): "InfinityValue",
|
||||
("read_only_space", 0x0132d): "MinusZeroValue",
|
||||
("read_only_space", 0x01339): "MinusInfinityValue",
|
||||
("read_only_space", 0x01345): "SelfReferenceMarker",
|
||||
("read_only_space", 0x01385): "BasicBlockCountersMarker",
|
||||
("read_only_space", 0x013c9): "OffHeapTrampolineRelocationInfo",
|
||||
("read_only_space", 0x013d5): "TrampolineTrivialCodeDataContainer",
|
||||
("read_only_space", 0x013e1): "TrampolinePromiseRejectionCodeDataContainer",
|
||||
("read_only_space", 0x013ed): "GlobalThisBindingScopeInfo",
|
||||
("read_only_space", 0x01425): "EmptyFunctionScopeInfo",
|
||||
("read_only_space", 0x0144d): "NativeScopeInfo",
|
||||
("read_only_space", 0x01469): "HashSeed",
|
||||
("old_space", 0x00121): "ArgumentsIteratorAccessor",
|
||||
("old_space", 0x00165): "ArrayLengthAccessor",
|
||||
("old_space", 0x001a9): "BoundFunctionLengthAccessor",
|
||||
|
Loading…
Reference in New Issue
Block a user