mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:09:48 +00:00
[vm] Treat the dispatch table as a root in the snapshot.
Additional changes: * Only serialize a dispatch table in precompiled snapshots. * Add information in v8 snapshot profiles for the dispatch table. * Fix a typo in a field name. * Print the number of Instructions objects (or payloads, for precompiled bare instructions mode) in the fake cluster for the data section. * Fix v8 snapshots profiles so objects in memory mapped segments and only those are prefixed with "(RO) ". * Add names for Instructions objects in v8 snapshot profiles when we can use the assembly namer. * Add command line flag for old #define'd false flag. Change-Id: I1e3be59c7a6312efd76afca560ba465cc17cb22b Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm_x64-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-precomp-mac-release-simarm64-try,vm-kernel-precomp-win-release-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/138089 Commit-Queue: Teagan Strickland <sstrickl@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Aske Simon Christensen <askesc@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
a5bf30c401
commit
ba68d04d3f
|
@ -27,10 +27,15 @@
|
|||
#include "vm/timeline.h"
|
||||
#include "vm/version.h"
|
||||
|
||||
#define LOG_SECTION_BOUNDARIES false
|
||||
|
||||
namespace dart {
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
DEFINE_FLAG(bool,
|
||||
print_cluster_information,
|
||||
false,
|
||||
"Print information about clusters written to snapshot");
|
||||
#endif
|
||||
|
||||
#if defined(DART_PRECOMPILER)
|
||||
DEFINE_FLAG(charp,
|
||||
write_v8_snapshot_profile_to,
|
||||
|
@ -101,27 +106,34 @@ void Deserializer::InitializeHeader(RawObject* raw,
|
|||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
void SerializationCluster::WriteAndMeasureAlloc(Serializer* serializer) {
|
||||
if (LOG_SECTION_BOUNDARIES) {
|
||||
OS::PrintErr("Data + %" Px ": Alloc %s\n", serializer->bytes_written(),
|
||||
name_);
|
||||
}
|
||||
intptr_t start_size = serializer->bytes_written() + serializer->GetDataSize();
|
||||
intptr_t start_size = serializer->bytes_written();
|
||||
intptr_t start_data = serializer->GetDataSize();
|
||||
intptr_t start_objects = serializer->next_ref_index();
|
||||
WriteAlloc(serializer);
|
||||
intptr_t stop_size = serializer->bytes_written() + serializer->GetDataSize();
|
||||
intptr_t stop_size = serializer->bytes_written();
|
||||
intptr_t stop_data = serializer->GetDataSize();
|
||||
intptr_t stop_objects = serializer->next_ref_index();
|
||||
size_ += (stop_size - start_size);
|
||||
if (FLAG_print_cluster_information) {
|
||||
const int hex_size = kWordSize * 2;
|
||||
OS::PrintErr("Snapshot 0x%0*.*" Px " (%" Pd "), ", hex_size, hex_size,
|
||||
start_size, stop_size - start_size);
|
||||
OS::PrintErr("Data 0x%0*.*" Px " (%" Pd "): ", hex_size, hex_size,
|
||||
start_data, stop_data - start_data);
|
||||
OS::PrintErr("Alloc %s (%" Pd ")\n", name(), stop_objects - start_objects);
|
||||
}
|
||||
size_ += (stop_size - start_size) + (stop_data - start_data);
|
||||
num_objects_ += (stop_objects - start_objects);
|
||||
}
|
||||
|
||||
void SerializationCluster::WriteAndMeasureFill(Serializer* serializer) {
|
||||
if (LOG_SECTION_BOUNDARIES) {
|
||||
OS::PrintErr("Data + %" Px ": Fill %s\n", serializer->bytes_written(),
|
||||
name_);
|
||||
}
|
||||
intptr_t start = serializer->bytes_written();
|
||||
WriteFill(serializer);
|
||||
intptr_t stop = serializer->bytes_written();
|
||||
if (FLAG_print_cluster_information) {
|
||||
const int hex_size = kWordSize * 2;
|
||||
OS::PrintErr("Snapshot 0x%0*.*" Px " (%" Pd "): Fill %s\n", hex_size,
|
||||
hex_size, start, stop - start, name());
|
||||
}
|
||||
size_ += (stop - start);
|
||||
}
|
||||
|
||||
|
@ -2008,8 +2020,11 @@ class PcDescriptorsDeserializationCluster : public DeserializationCluster {
|
|||
// PcDescriptor, CompressedStackMaps, OneByteString, TwoByteString
|
||||
class RODataSerializationCluster : public SerializationCluster {
|
||||
public:
|
||||
RODataSerializationCluster(const char* name, intptr_t cid)
|
||||
: SerializationCluster(name), cid_(cid) {}
|
||||
RODataSerializationCluster(Zone* zone, const char* type, intptr_t cid)
|
||||
: SerializationCluster(ImageWriter::TagObjectTypeAsReadOnly(zone, type)),
|
||||
cid_(cid),
|
||||
objects_(),
|
||||
type_(type) {}
|
||||
~RODataSerializationCluster() {}
|
||||
|
||||
void Trace(Serializer* s, RawObject* object) {
|
||||
|
@ -2037,9 +2052,9 @@ class RODataSerializationCluster : public SerializationCluster {
|
|||
RawObject* object = objects_[i];
|
||||
s->AssignRef(object);
|
||||
if (cid_ == kOneByteStringCid || cid_ == kTwoByteStringCid) {
|
||||
s->TraceStartWritingObject(name(), object, String::RawCast(object));
|
||||
s->TraceStartWritingObject(type_, object, String::RawCast(object));
|
||||
} else {
|
||||
s->TraceStartWritingObject(name(), object, nullptr);
|
||||
s->TraceStartWritingObject(type_, object, nullptr);
|
||||
}
|
||||
uint32_t offset = s->GetDataOffset(object);
|
||||
s->TraceDataOffset(offset);
|
||||
|
@ -2060,6 +2075,7 @@ class RODataSerializationCluster : public SerializationCluster {
|
|||
private:
|
||||
const intptr_t cid_;
|
||||
GrowableArray<RawObject*> objects_;
|
||||
const char* const type_;
|
||||
};
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
|
||||
|
@ -4565,6 +4581,23 @@ void Serializer::TraceEndWritingObject() {
|
|||
}
|
||||
}
|
||||
|
||||
const char* Serializer::ReadOnlyObjectType(intptr_t cid) {
|
||||
switch (cid) {
|
||||
case kPcDescriptorsCid:
|
||||
return "PcDescriptors";
|
||||
case kCodeSourceMapCid:
|
||||
return "CodeSourceMap";
|
||||
case kCompressedStackMapsCid:
|
||||
return "CompressedStackMaps";
|
||||
case kOneByteStringCid:
|
||||
return "OneByteString";
|
||||
case kTwoByteStringCid:
|
||||
return "TwoByteString";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
UNREACHABLE();
|
||||
|
@ -4586,18 +4619,8 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
|
|||
}
|
||||
|
||||
if (Snapshot::IncludesCode(kind_)) {
|
||||
switch (cid) {
|
||||
case kPcDescriptorsCid:
|
||||
return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
|
||||
case kCodeSourceMapCid:
|
||||
return new (Z) RODataSerializationCluster("(RO)CodeSourceMap", cid);
|
||||
case kCompressedStackMapsCid:
|
||||
return new (Z)
|
||||
RODataSerializationCluster("(RO)CompressedStackMaps", cid);
|
||||
case kOneByteStringCid:
|
||||
return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
|
||||
case kTwoByteStringCid:
|
||||
return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
|
||||
if (auto const type = ReadOnlyObjectType(cid)) {
|
||||
return new (Z) RODataSerializationCluster(Z, type, cid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4792,13 +4815,6 @@ intptr_t Serializer::GetDataSize() const {
|
|||
return image_writer_->data_size();
|
||||
}
|
||||
|
||||
intptr_t Serializer::GetTextSize() const {
|
||||
if (image_writer_ == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return image_writer_->text_size();
|
||||
}
|
||||
|
||||
void Serializer::Push(RawObject* object) {
|
||||
if (!object->IsHeapObject()) {
|
||||
RawSmi* smi = Smi::RawCast(object);
|
||||
|
@ -5030,19 +5046,36 @@ void Serializer::PrintSnapshotSizes() {
|
|||
clusters_by_size.Add(cluster);
|
||||
}
|
||||
}
|
||||
if (GetTextSize() != 0) {
|
||||
intptr_t text_size = 0;
|
||||
if (image_writer_ != nullptr) {
|
||||
auto const text_object_count = image_writer_->GetTextObjectCount();
|
||||
text_size = image_writer_->text_size();
|
||||
intptr_t trampoline_count, trampoline_size;
|
||||
image_writer_->GetTrampolineInfo(&trampoline_count, &trampoline_size);
|
||||
auto const instructions_count = text_object_count - trampoline_count;
|
||||
auto const instructions_size = text_size - trampoline_size;
|
||||
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
|
||||
"(RO)Instructions", 0, GetTextSize()));
|
||||
ImageWriter::TagObjectTypeAsReadOnly(zone_, "Instructions"),
|
||||
instructions_count, instructions_size));
|
||||
if (trampoline_size > 0) {
|
||||
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
|
||||
ImageWriter::TagObjectTypeAsReadOnly(zone_, "Trampoline"),
|
||||
trampoline_count, trampoline_size));
|
||||
}
|
||||
}
|
||||
// An null dispatch table will serialize to a single byte.
|
||||
if (dispatch_table_size_ > 1) {
|
||||
// The dispatch_table_size_ will be 0 if the snapshot did not include a
|
||||
// dispatch table (i.e., the VM snapshot). For a precompiled isolate
|
||||
// snapshot, we always serialize at least _one_ byte for the DispatchTable.
|
||||
if (dispatch_table_size_ > 0) {
|
||||
auto const dispatch_table = isolate()->dispatch_table();
|
||||
auto const entry_count =
|
||||
dispatch_table != nullptr ? dispatch_table->length() : 0;
|
||||
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
|
||||
"(RO)DispatchTable", isolate()->dispatch_table()->length(),
|
||||
dispatch_table_size_));
|
||||
"DispatchTable", entry_count, dispatch_table_size_));
|
||||
}
|
||||
clusters_by_size.Sort(CompareClusters);
|
||||
double total_size =
|
||||
static_cast<double>(bytes_written() + GetDataSize() + GetTextSize());
|
||||
static_cast<double>(bytes_written() + GetDataSize() + text_size);
|
||||
double cumulative_fraction = 0.0;
|
||||
for (intptr_t i = 0; i < clusters_by_size.length(); i++) {
|
||||
SerializationCluster* cluster = clusters_by_size[i];
|
||||
|
@ -5178,6 +5211,36 @@ static const char* kObjectStoreFieldNames[] = {
|
|||
|
||||
void Serializer::WriteIsolateSnapshot(intptr_t num_base_objects,
|
||||
ObjectStore* object_store) {
|
||||
#if defined(DART_PRECOMPILER)
|
||||
// We should treat the dispatch table as a root object and trace the
|
||||
// Code objects it references via entry points. Otherwise, an non-empty
|
||||
// entry could be invalid on deserialization if the corresponding Code
|
||||
// object was not reachable from the existing snapshot roots.
|
||||
//
|
||||
// Since the dispatch table only stores entry points, we have to find the
|
||||
// Code objects before entering the NoSafepointScope, since looking up a
|
||||
// Code object from the entry point cannot be done during one.
|
||||
auto const dispatch_table = isolate()->dispatch_table();
|
||||
// Check that we only have dispatch tables in precompiled mode, so we can
|
||||
// elide them from the snapshot when not creating a precompiled snapshot.
|
||||
ASSERT(dispatch_table == nullptr || kind() == Snapshot::kFullAOT);
|
||||
// We collect the Code objects for each entry, storing null if there is none.
|
||||
auto const dispatch_table_length =
|
||||
dispatch_table != nullptr ? dispatch_table->length() : 0;
|
||||
GrowableHandlePtrArray<const Code> dispatch_table_roots(
|
||||
zone_, dispatch_table_length);
|
||||
if (dispatch_table != nullptr) {
|
||||
auto& code = Code::Handle(zone_);
|
||||
auto const entries = dispatch_table->array();
|
||||
for (intptr_t i = 0; i < dispatch_table_length; i++) {
|
||||
auto const entry = entries[i];
|
||||
code = entry != 0 ? Code::LookupCode(entry) : Code::null();
|
||||
ASSERT(entry == 0 || !code.IsNull());
|
||||
dispatch_table_roots.Add(code);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NoSafepointScope no_safepoint;
|
||||
|
||||
if (num_base_objects == 0) {
|
||||
|
@ -5199,6 +5262,15 @@ void Serializer::WriteIsolateSnapshot(intptr_t num_base_objects,
|
|||
Push(*p);
|
||||
}
|
||||
|
||||
#if defined(DART_PRECOMPILER)
|
||||
// Push the Code objects collected from the dispatch table.
|
||||
for (intptr_t i = 0; i < dispatch_table_length; i++) {
|
||||
const auto& code = dispatch_table_roots.At(i);
|
||||
if (code.IsNull()) continue;
|
||||
Push(code.raw());
|
||||
}
|
||||
#endif
|
||||
|
||||
Serialize();
|
||||
|
||||
// Write roots.
|
||||
|
@ -5206,12 +5278,37 @@ void Serializer::WriteIsolateSnapshot(intptr_t num_base_objects,
|
|||
WriteRootRef(*p, kObjectStoreFieldNames[p - from]);
|
||||
}
|
||||
|
||||
// Serialize dispatch table.
|
||||
GrowableArray<RawCode*>* code_objects =
|
||||
static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid])
|
||||
->discovered_objects();
|
||||
dispatch_table_size_ = DispatchTable::Serialize(
|
||||
this, isolate()->dispatch_table(), *code_objects);
|
||||
#if defined(DART_PRECOMPILER)
|
||||
// Serialize dispatch table for precompiled snapshots only.
|
||||
if (kind() == Snapshot::kFullAOT) {
|
||||
GrowableArray<RawCode*>* code_objects =
|
||||
static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid])
|
||||
->discovered_objects();
|
||||
dispatch_table_size_ = DispatchTable::Serialize(
|
||||
this, isolate()->dispatch_table(), *code_objects);
|
||||
ASSERT(dispatch_table_length == 0 || dispatch_table_size_ > 1);
|
||||
|
||||
if (profile_writer_ != nullptr) {
|
||||
// Grab an unused ref index for a unique object id for the dispatch table.
|
||||
const auto dispatch_table_id = next_ref_index_++;
|
||||
const V8SnapshotProfileWriter::ObjectId dispatch_table_snapshot_id(
|
||||
V8SnapshotProfileWriter::kSnapshot, dispatch_table_id);
|
||||
profile_writer_->AddRoot(dispatch_table_snapshot_id, "dispatch_table");
|
||||
profile_writer_->SetObjectTypeAndName(dispatch_table_snapshot_id,
|
||||
"DispatchTable", nullptr);
|
||||
profile_writer_->AttributeBytesTo(dispatch_table_snapshot_id,
|
||||
dispatch_table_size_);
|
||||
for (intptr_t i = 0; i < dispatch_table_length; i++) {
|
||||
const auto& code = dispatch_table_roots.At(i);
|
||||
const V8SnapshotProfileWriter::ObjectId code_id(
|
||||
V8SnapshotProfileWriter::kSnapshot, WriteRefId(code.raw()));
|
||||
profile_writer_->AttributeReferenceTo(
|
||||
dispatch_table_snapshot_id,
|
||||
{code_id, V8SnapshotProfileWriter::Reference::kElement, i});
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
Write<int32_t>(kSectionMarker);
|
||||
|
@ -5776,11 +5873,13 @@ void Deserializer::ReadIsolateSnapshot(ObjectStore* object_store) {
|
|||
*p = ReadRef();
|
||||
}
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
// Deserialize dispatch table
|
||||
const Array& code_array =
|
||||
Array::Handle(zone_, object_store->code_order_table());
|
||||
thread()->isolate()->set_dispatch_table(
|
||||
DispatchTable::Deserialize(this, code_array));
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
int32_t section_marker = Read<int32_t>();
|
||||
|
|
|
@ -246,36 +246,6 @@ class Serializer : public ThreadStackResource {
|
|||
}
|
||||
void Align(intptr_t alignment) { stream_.Align(alignment); }
|
||||
|
||||
private:
|
||||
intptr_t WriteRefId(RawObject* object) {
|
||||
intptr_t id = 0;
|
||||
if (!object->IsHeapObject()) {
|
||||
RawSmi* smi = Smi::RawCast(object);
|
||||
id = smi_ids_.Lookup(smi)->id_;
|
||||
if (id == 0) {
|
||||
FATAL("Missing ref");
|
||||
}
|
||||
} else {
|
||||
// The object id weak table holds image offsets for Instructions instead
|
||||
// of ref indices.
|
||||
ASSERT(!object->IsInstructions());
|
||||
id = heap_->GetObjectId(object);
|
||||
if (id == 0) {
|
||||
if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
|
||||
return WriteRefId(Object::null());
|
||||
}
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (object->IsBytecode() && !Snapshot::IncludesBytecode(kind_)) {
|
||||
return WriteRefId(Object::null());
|
||||
}
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
FATAL("Missing ref");
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public:
|
||||
void WriteRootRef(RawObject* object, const char* name = nullptr) {
|
||||
intptr_t id = WriteRefId(object);
|
||||
WriteUnsigned(id);
|
||||
|
@ -382,7 +352,6 @@ class Serializer : public ThreadStackResource {
|
|||
uint32_t GetDataOffset(RawObject* object) const;
|
||||
void TraceDataOffset(uint32_t offset);
|
||||
intptr_t GetDataSize() const;
|
||||
intptr_t GetTextSize() const;
|
||||
|
||||
Snapshot::Kind kind() const { return kind_; }
|
||||
intptr_t next_ref_index() const { return next_ref_index_; }
|
||||
|
@ -390,6 +359,36 @@ class Serializer : public ThreadStackResource {
|
|||
void DumpCombinedCodeStatistics();
|
||||
|
||||
private:
|
||||
static const char* ReadOnlyObjectType(intptr_t cid);
|
||||
|
||||
intptr_t WriteRefId(RawObject* object) {
|
||||
intptr_t id = 0;
|
||||
if (!object->IsHeapObject()) {
|
||||
RawSmi* smi = Smi::RawCast(object);
|
||||
id = smi_ids_.Lookup(smi)->id_;
|
||||
if (id == 0) {
|
||||
FATAL("Missing ref");
|
||||
}
|
||||
} else {
|
||||
// The object id weak table holds image offsets for Instructions instead
|
||||
// of ref indices.
|
||||
ASSERT(!object->IsInstructions());
|
||||
id = heap_->GetObjectId(object);
|
||||
if (id == 0) {
|
||||
if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
|
||||
return WriteRefId(Object::null());
|
||||
}
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (object->IsBytecode() && !Snapshot::IncludesBytecode(kind_)) {
|
||||
return WriteRefId(Object::null());
|
||||
}
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
FATAL("Missing ref");
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
Heap* heap_;
|
||||
Zone* zone_;
|
||||
Snapshot::Kind kind_;
|
||||
|
|
|
@ -292,7 +292,7 @@ void Dwarf::WriteCompilationUnit() {
|
|||
uint8_t* buffer = nullptr;
|
||||
WriteStream stream(&buffer, ZoneReallocate, 64 * KB);
|
||||
|
||||
AssemblyCodeNamer namer(zone_);
|
||||
SnapshotTextObjectNamer namer(zone_);
|
||||
|
||||
if (asm_stream_ != nullptr) {
|
||||
#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
|
||||
|
@ -358,7 +358,7 @@ void Dwarf::WriteCompilationUnit() {
|
|||
intptr_t last_code_index = codes_.length() - 1;
|
||||
const Code& last_code = *(codes_[last_code_index]);
|
||||
PrintNamedAddressWithOffset(
|
||||
namer.AssemblyNameFor(last_code_index, last_code), last_code.Size());
|
||||
namer.SnapshotNameFor(last_code_index, last_code), last_code.Size());
|
||||
}
|
||||
if (elf_ != nullptr) {
|
||||
addr(elf_->NextMemoryOffset());
|
||||
|
@ -421,7 +421,7 @@ void Dwarf::WriteAbstractFunctions() {
|
|||
void Dwarf::WriteConcreteFunctions() {
|
||||
Function& function = Function::Handle(zone_);
|
||||
Script& script = Script::Handle(zone_);
|
||||
AssemblyCodeNamer namer(zone_);
|
||||
SnapshotTextObjectNamer namer(zone_);
|
||||
for (intptr_t i = 0; i < codes_.length(); i++) {
|
||||
const Code& code = *(codes_[i]);
|
||||
RELEASE_ASSERT(!code.IsNull());
|
||||
|
@ -456,7 +456,7 @@ void Dwarf::WriteConcreteFunctions() {
|
|||
|
||||
// DW_AT_low_pc
|
||||
if (asm_stream_ != nullptr) {
|
||||
const char* asm_name = namer.AssemblyNameFor(i, code);
|
||||
const char* asm_name = namer.SnapshotNameFor(i, code);
|
||||
// DW_AT_low_pc
|
||||
PrintNamedAddress(asm_name);
|
||||
// DW_AT_high_pc
|
||||
|
@ -564,7 +564,7 @@ void Dwarf::WriteInliningNode(InliningNode* node,
|
|||
intptr_t root_code_index,
|
||||
intptr_t root_code_address,
|
||||
const Script& parent_script,
|
||||
AssemblyCodeNamer* namer) {
|
||||
SnapshotTextObjectNamer* namer) {
|
||||
RELEASE_ASSERT(elf_ == nullptr || root_code_address >= 0);
|
||||
intptr_t file = LookupScript(parent_script);
|
||||
intptr_t line = node->call_pos.value();
|
||||
|
@ -587,7 +587,7 @@ void Dwarf::WriteInliningNode(InliningNode* node,
|
|||
|
||||
if (asm_stream_ != nullptr) {
|
||||
const char* asm_name =
|
||||
namer->AssemblyNameFor(root_code_index, *codes_[root_code_index]);
|
||||
namer->SnapshotNameFor(root_code_index, *codes_[root_code_index]);
|
||||
// DW_AT_low_pc
|
||||
PrintNamedAddressWithOffset(asm_name, node->start_pc_offset);
|
||||
// DW_AT_high_pc
|
||||
|
@ -722,14 +722,14 @@ void Dwarf::WriteLines() {
|
|||
Array& functions = Array::Handle(zone_);
|
||||
GrowableArray<const Function*> function_stack(zone_, 8);
|
||||
GrowableArray<TokenPosition> token_positions(zone_, 8);
|
||||
AssemblyCodeNamer namer(zone_);
|
||||
SnapshotTextObjectNamer namer(zone_);
|
||||
|
||||
for (intptr_t i = 0; i < codes_.length(); i++) {
|
||||
const Code& code = *(codes_[i]);
|
||||
|
||||
const char* asm_name = nullptr;
|
||||
if (asm_stream_ != nullptr) {
|
||||
asm_name = namer.AssemblyNameFor(i, code);
|
||||
asm_name = namer.SnapshotNameFor(i, code);
|
||||
}
|
||||
|
||||
intptr_t current_code_address = -1;
|
||||
|
@ -808,7 +808,7 @@ void Dwarf::WriteLines() {
|
|||
} else {
|
||||
u1(DW_LNS_advance_pc);
|
||||
if (asm_stream_ != nullptr) {
|
||||
const char* previous_asm_name = namer.AssemblyNameFor(
|
||||
const char* previous_asm_name = namer.SnapshotNameFor(
|
||||
previous_code_index, *codes_[previous_code_index]);
|
||||
Print(".uleb128 %s - %s + %" Pd "\n", asm_name, previous_asm_name,
|
||||
current_pc_offset - previous_pc_offset);
|
||||
|
@ -859,9 +859,9 @@ void Dwarf::WriteLines() {
|
|||
u1(DW_LNS_advance_pc);
|
||||
if (asm_stream_ != nullptr) {
|
||||
const char* last_asm_name =
|
||||
namer.AssemblyNameFor(last_code_index, last_code);
|
||||
namer.SnapshotNameFor(last_code_index, last_code);
|
||||
ASSERT(previous_code_index >= 0);
|
||||
const char* previous_asm_name = namer.AssemblyNameFor(
|
||||
const char* previous_asm_name = namer.SnapshotNameFor(
|
||||
previous_code_index, *codes_[previous_code_index]);
|
||||
Print(".uleb128 %s - %s + %" Pd "\n", last_asm_name, previous_asm_name,
|
||||
last_code.Size() - previous_pc_offset);
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace dart {
|
|||
|
||||
class Elf;
|
||||
class InliningNode;
|
||||
class AssemblyCodeNamer;
|
||||
class SnapshotTextObjectNamer;
|
||||
|
||||
struct ScriptIndexPair {
|
||||
// Typedefs needed for the DirectChainedHashMap template.
|
||||
|
@ -393,7 +393,7 @@ class Dwarf : public ZoneAllocated {
|
|||
intptr_t root_code_index,
|
||||
intptr_t root_code_offset,
|
||||
const Script& parent_script,
|
||||
AssemblyCodeNamer* namer);
|
||||
SnapshotTextObjectNamer* namer);
|
||||
void WriteLines();
|
||||
|
||||
const char* Deobfuscate(const char* cstr);
|
||||
|
|
|
@ -78,15 +78,21 @@ bool ObjectOffsetTrait::IsKeyEqual(Pair pair, Key key) {
|
|||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
ImageWriter::ImageWriter(Heap* heap)
|
||||
: heap_(heap),
|
||||
ImageWriter::ImageWriter(Thread* t)
|
||||
: heap_(t->heap()),
|
||||
next_data_offset_(0),
|
||||
next_text_offset_(0),
|
||||
objects_(),
|
||||
instructions_() {
|
||||
instructions_(),
|
||||
instructions_section_type_(
|
||||
TagObjectTypeAsReadOnly(t->zone(), "InstructionsSection")),
|
||||
instructions_type_(TagObjectTypeAsReadOnly(t->zone(), "Instructions")),
|
||||
trampoline_type_(TagObjectTypeAsReadOnly(t->zone(), "Trampoline")) {
|
||||
ResetOffsets();
|
||||
}
|
||||
|
||||
ImageWriter::~ImageWriter() {}
|
||||
|
||||
void ImageWriter::PrepareForSerialization(
|
||||
GrowableArray<ImageWriterCommand>* commands) {
|
||||
if (commands != nullptr) {
|
||||
|
@ -243,6 +249,42 @@ uint32_t ImageWriter::GetDataOffsetFor(RawObject* raw_object) {
|
|||
return offset;
|
||||
}
|
||||
|
||||
intptr_t ImageWriter::GetTextObjectCount() const {
|
||||
return instructions_.length();
|
||||
}
|
||||
|
||||
void ImageWriter::GetTrampolineInfo(intptr_t* count, intptr_t* size) const {
|
||||
ASSERT(count != nullptr && size != nullptr);
|
||||
*count = 0;
|
||||
*size = 0;
|
||||
for (auto const data : instructions_) {
|
||||
if (data.trampoline_length != 0) {
|
||||
*count += 1;
|
||||
*size += data.trampoline_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns nullptr if there is no profile writer.
|
||||
const char* ImageWriter::ObjectTypeForProfile(const Object& object) const {
|
||||
if (profile_writer_ == nullptr) return nullptr;
|
||||
ASSERT(IsROSpace());
|
||||
Thread* thread = Thread::Current();
|
||||
REUSABLE_CLASS_HANDLESCOPE(thread);
|
||||
REUSABLE_STRING_HANDLESCOPE(thread);
|
||||
Class& klass = thread->ClassHandle();
|
||||
String& name = thread->StringHandle();
|
||||
klass = object.clazz();
|
||||
name = klass.UserVisibleName();
|
||||
auto const name_str = name.ToCString();
|
||||
return TagObjectTypeAsReadOnly(thread->zone(), name_str);
|
||||
}
|
||||
|
||||
const char* ImageWriter::TagObjectTypeAsReadOnly(Zone* zone, const char* type) {
|
||||
ASSERT(zone != nullptr && type != nullptr);
|
||||
return OS::SCreate(zone, "(RO) %s", type);
|
||||
}
|
||||
|
||||
#if defined(DART_PRECOMPILER)
|
||||
void ImageWriter::DumpInstructionStats() {
|
||||
std::unique_ptr<CombinedCodeStatistics> instruction_stats(
|
||||
|
@ -461,7 +503,7 @@ AssemblyImageWriter::AssemblyImageWriter(Thread* thread,
|
|||
void* callback_data,
|
||||
bool strip,
|
||||
Elf* debug_elf)
|
||||
: ImageWriter(thread->heap()),
|
||||
: ImageWriter(thread),
|
||||
assembly_stream_(512 * KB, callback, callback_data),
|
||||
assembly_dwarf_(nullptr),
|
||||
debug_dwarf_(nullptr) {
|
||||
|
@ -537,37 +579,47 @@ static const char* NameOfStubIsolateSpecificStub(ObjectStore* object_store,
|
|||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
const char* AssemblyCodeNamer::AssemblyNameFor(intptr_t code_index,
|
||||
const Code& code) {
|
||||
const char* SnapshotTextObjectNamer::SnapshotNameFor(intptr_t code_index,
|
||||
const Code& code) {
|
||||
ASSERT(!code.IsNull());
|
||||
const char* prefix = FLAG_precompiled_mode ? "Precompiled_" : "";
|
||||
owner_ = code.owner();
|
||||
if (owner_.IsNull()) {
|
||||
insns_ = code.instructions();
|
||||
const char* name = StubCode::NameOfStub(insns_.EntryPoint());
|
||||
if (name != nullptr) {
|
||||
return OS::SCreate(zone_, "Precompiled_Stub_%s", name);
|
||||
return OS::SCreate(zone_, "%sStub_%s", prefix, name);
|
||||
}
|
||||
name = NameOfStubIsolateSpecificStub(store_, code);
|
||||
ASSERT(name != nullptr);
|
||||
return OS::SCreate(zone_, "Precompiled__%s", name);
|
||||
return OS::SCreate(zone_, "%s_%s", prefix, name);
|
||||
} else if (owner_.IsClass()) {
|
||||
string_ = Class::Cast(owner_).Name();
|
||||
const char* name = string_.ToCString();
|
||||
EnsureAssemblerIdentifier(const_cast<char*>(name));
|
||||
return OS::SCreate(zone_, "Precompiled_AllocationStub_%s_%" Pd, name,
|
||||
return OS::SCreate(zone_, "%sAllocationStub_%s_%" Pd, prefix, name,
|
||||
code_index);
|
||||
} else if (owner_.IsAbstractType()) {
|
||||
const char* name = namer_.StubNameForType(AbstractType::Cast(owner_));
|
||||
return OS::SCreate(zone_, "Precompiled_%s", name);
|
||||
return OS::SCreate(zone_, "%s%s", prefix, name);
|
||||
} else if (owner_.IsFunction()) {
|
||||
const char* name = Function::Cast(owner_).ToQualifiedCString();
|
||||
EnsureAssemblerIdentifier(const_cast<char*>(name));
|
||||
return OS::SCreate(zone_, "Precompiled_%s_%" Pd, name, code_index);
|
||||
return OS::SCreate(zone_, "%s%s_%" Pd, prefix, name, code_index);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
const char* SnapshotTextObjectNamer::SnapshotNameFor(
|
||||
intptr_t index,
|
||||
const ImageWriter::InstructionsData& data) {
|
||||
if (data.trampoline_bytes != nullptr) {
|
||||
return OS::SCreate(zone_, "Trampoline_%" Pd "", index);
|
||||
}
|
||||
return SnapshotNameFor(index, *data.code_);
|
||||
}
|
||||
|
||||
void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
UNREACHABLE();
|
||||
|
@ -614,6 +666,10 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
WriteWordLiteralText(0);
|
||||
}
|
||||
|
||||
// Only valid if bare_instruction_payloads is true.
|
||||
const V8SnapshotProfileWriter::ObjectId instructions_section_id(
|
||||
offset_space_, bare_instruction_payloads ? Image::kHeaderSize : -1);
|
||||
|
||||
if (bare_instruction_payloads) {
|
||||
const intptr_t section_size = image_size - Image::kHeaderSize;
|
||||
// Add the RawInstructionsSection header.
|
||||
|
@ -633,15 +689,14 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
WriteWordLiteralText(instructions_length);
|
||||
|
||||
if (profile_writer_ != nullptr) {
|
||||
const intptr_t offset = Image::kHeaderSize;
|
||||
const intptr_t non_instruction_bytes =
|
||||
compiler::target::InstructionsSection::HeaderSize();
|
||||
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
|
||||
"InstructionsSection",
|
||||
/*name=*/nullptr);
|
||||
profile_writer_->AttributeBytesTo({offset_space_, offset},
|
||||
profile_writer_->SetObjectTypeAndName(instructions_section_id,
|
||||
instructions_section_type_,
|
||||
instructions_symbol);
|
||||
profile_writer_->AttributeBytesTo(instructions_section_id,
|
||||
non_instruction_bytes);
|
||||
profile_writer_->AddRoot({offset_space_, offset});
|
||||
profile_writer_->AddRoot(instructions_section_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -654,7 +709,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
FrameUnwindPrologue();
|
||||
|
||||
PcDescriptors& descriptors = PcDescriptors::Handle(zone);
|
||||
AssemblyCodeNamer namer(zone);
|
||||
SnapshotTextObjectNamer namer(zone);
|
||||
intptr_t text_offset = 0;
|
||||
|
||||
ASSERT(offset_space_ != V8SnapshotProfileWriter::kSnapshot);
|
||||
|
@ -663,28 +718,37 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
const bool is_trampoline = data.trampoline_bytes != nullptr;
|
||||
ASSERT((data.text_offset_ - instructions_[0].text_offset_) == text_offset);
|
||||
|
||||
if (bare_instruction_payloads && profile_writer_ != nullptr) {
|
||||
const intptr_t instructions_sections_offset = Image::kHeaderSize;
|
||||
const intptr_t offset = section_headers_size + text_offset;
|
||||
profile_writer_->AttributeReferenceTo(
|
||||
{offset_space_, instructions_sections_offset},
|
||||
{{offset_space_, offset},
|
||||
V8SnapshotProfileWriter::Reference::kElement,
|
||||
text_offset});
|
||||
intptr_t dwarf_index = i;
|
||||
#if defined(DART_PRECOMPILER)
|
||||
if (!is_trampoline && assembly_dwarf_ != nullptr) {
|
||||
dwarf_index = assembly_dwarf_->AddCode(*data.code_);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto object_name = namer.SnapshotNameFor(dwarf_index, data);
|
||||
|
||||
if (profile_writer_ != nullptr) {
|
||||
const auto object_offset = section_headers_size + text_offset;
|
||||
const V8SnapshotProfileWriter::ObjectId object_id(offset_space_,
|
||||
object_offset);
|
||||
auto const type = is_trampoline ? trampoline_type_ : instructions_type_;
|
||||
const intptr_t size = is_trampoline ? data.trampoline_length
|
||||
: SizeInSnapshot(data.insns_->raw());
|
||||
profile_writer_->SetObjectTypeAndName(object_id, type, object_name);
|
||||
profile_writer_->AttributeBytesTo(object_id, size);
|
||||
// If the object is wrapped in an InstructionSection, then add an
|
||||
// element reference.
|
||||
if (bare_instruction_payloads) {
|
||||
profile_writer_->AttributeReferenceTo(
|
||||
instructions_section_id,
|
||||
{object_id, V8SnapshotProfileWriter::Reference::kElement,
|
||||
text_offset});
|
||||
}
|
||||
}
|
||||
|
||||
if (is_trampoline) {
|
||||
if (profile_writer_ != nullptr) {
|
||||
const intptr_t offset = section_headers_size + text_offset;
|
||||
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
|
||||
"Trampolines",
|
||||
/*name=*/nullptr);
|
||||
profile_writer_->AttributeBytesTo({offset_space_, offset},
|
||||
data.trampline_length);
|
||||
}
|
||||
|
||||
const auto start = reinterpret_cast<uword>(data.trampoline_bytes);
|
||||
const auto end = start + data.trampline_length;
|
||||
const auto end = start + data.trampoline_length;
|
||||
text_offset += WriteByteSequence(start, end);
|
||||
delete[] data.trampoline_bytes;
|
||||
data.trampoline_bytes = nullptr;
|
||||
|
@ -694,18 +758,8 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
const intptr_t instr_start = text_offset;
|
||||
|
||||
const Instructions& insns = *data.insns_;
|
||||
const Code& code = *data.code_;
|
||||
descriptors = data.code_->pc_descriptors();
|
||||
|
||||
if (profile_writer_ != nullptr) {
|
||||
const intptr_t offset = section_headers_size + text_offset;
|
||||
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
|
||||
"Instructions",
|
||||
/*name=*/nullptr);
|
||||
profile_writer_->AttributeBytesTo({offset_space_, offset},
|
||||
SizeInSnapshot(insns.raw()));
|
||||
}
|
||||
|
||||
const uword payload_start = insns.PayloadStart();
|
||||
|
||||
// 1. Write from the object start to the payload start. This includes the
|
||||
|
@ -746,21 +800,16 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
compiler::target::Instructions::HeaderSize());
|
||||
}
|
||||
|
||||
intptr_t dwarf_index = i;
|
||||
#ifdef DART_PRECOMPILER
|
||||
// Create a label for use by DWARF.
|
||||
if (assembly_dwarf_ != nullptr) {
|
||||
dwarf_index = assembly_dwarf_->AddCode(code);
|
||||
}
|
||||
#if defined(DART_PRECOMPILER)
|
||||
if (debug_dwarf_ != nullptr) {
|
||||
auto const virtual_address =
|
||||
debug_segment_base + section_headers_size + text_offset;
|
||||
debug_dwarf_->AddCode(code, virtual_address);
|
||||
debug_dwarf_->AddCode(*data.code_, virtual_address);
|
||||
}
|
||||
#endif
|
||||
// 2. Write a label at the entry point.
|
||||
// Linux's perf uses these labels.
|
||||
assembly_stream_.Print("%s:\n", namer.AssemblyNameFor(dwarf_index, code));
|
||||
assembly_stream_.Print("%s:\n", object_name);
|
||||
|
||||
{
|
||||
// 3. Write from the payload start to payload end. For AOT snapshots
|
||||
|
@ -1005,7 +1054,7 @@ BlobImageWriter::BlobImageWriter(Thread* thread,
|
|||
intptr_t bss_base,
|
||||
Elf* elf,
|
||||
Dwarf* elf_dwarf)
|
||||
: ImageWriter(thread->heap()),
|
||||
: ImageWriter(thread),
|
||||
instructions_blob_stream_(instructions_blob_buffer, alloc, initial_size),
|
||||
elf_(elf),
|
||||
elf_dwarf_(elf_dwarf),
|
||||
|
@ -1030,8 +1079,11 @@ intptr_t BlobImageWriter::WriteByteSequence(uword start, uword end) {
|
|||
void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
||||
const bool bare_instruction_payloads =
|
||||
FLAG_precompiled_mode && FLAG_use_bare_instructions;
|
||||
const char* instructions_symbol =
|
||||
vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions";
|
||||
auto const zone = Thread::Current()->zone();
|
||||
|
||||
#ifdef DART_PRECOMPILER
|
||||
#if defined(DART_PRECOMPILER)
|
||||
intptr_t segment_base = 0;
|
||||
if (elf_ != nullptr) {
|
||||
segment_base = elf_->NextMemoryOffset();
|
||||
|
@ -1059,6 +1111,10 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
instructions_blob_stream_.WriteTargetWord(0);
|
||||
}
|
||||
|
||||
// Only valid when bare_instructions_payloads is true.
|
||||
const V8SnapshotProfileWriter::ObjectId instructions_section_id(
|
||||
offset_space_, bare_instruction_payloads ? Image::kHeaderSize : -1);
|
||||
|
||||
if (bare_instruction_payloads) {
|
||||
const intptr_t section_size = image_size - Image::kHeaderSize;
|
||||
// Add the RawInstructionsSection header.
|
||||
|
@ -1077,24 +1133,23 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
instructions_blob_stream_.WriteTargetWord(instructions_length);
|
||||
|
||||
if (profile_writer_ != nullptr) {
|
||||
const intptr_t offset = Image::kHeaderSize;
|
||||
const intptr_t non_instruction_bytes =
|
||||
compiler::target::InstructionsSection::HeaderSize();
|
||||
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
|
||||
"InstructionsSection",
|
||||
/*name=*/nullptr);
|
||||
profile_writer_->AttributeBytesTo({offset_space_, offset},
|
||||
profile_writer_->SetObjectTypeAndName(instructions_section_id,
|
||||
instructions_section_type_,
|
||||
instructions_symbol);
|
||||
profile_writer_->AttributeBytesTo(instructions_section_id,
|
||||
non_instruction_bytes);
|
||||
profile_writer_->AddRoot({offset_space_, offset});
|
||||
profile_writer_->AddRoot(instructions_section_id);
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t text_offset = 0;
|
||||
|
||||
#if defined(DART_PRECOMPILER)
|
||||
PcDescriptors& descriptors = PcDescriptors::Handle();
|
||||
AssemblyCodeNamer namer(Thread::Current()->zone());
|
||||
auto& descriptors = PcDescriptors::Handle(zone);
|
||||
#endif
|
||||
SnapshotTextObjectNamer namer(zone);
|
||||
|
||||
NoSafepointScope no_safepoint;
|
||||
for (intptr_t i = 0; i < instructions_.length(); i++) {
|
||||
|
@ -1102,18 +1157,29 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
const bool is_trampoline = data.trampoline_bytes != nullptr;
|
||||
ASSERT((data.text_offset_ - instructions_[0].text_offset_) == text_offset);
|
||||
|
||||
if (bare_instruction_payloads && profile_writer_ != nullptr) {
|
||||
const intptr_t instructions_sections_offset = Image::kHeaderSize;
|
||||
profile_writer_->AttributeReferenceTo(
|
||||
{offset_space_, instructions_sections_offset},
|
||||
{{offset_space_, instructions_blob_stream_.Position()},
|
||||
V8SnapshotProfileWriter::Reference::kElement,
|
||||
text_offset});
|
||||
const auto object_name = namer.SnapshotNameFor(i, data);
|
||||
|
||||
if (profile_writer_ != nullptr) {
|
||||
const V8SnapshotProfileWriter::ObjectId object_id(
|
||||
offset_space_, instructions_blob_stream_.Position());
|
||||
auto const type = is_trampoline ? trampoline_type_ : instructions_type_;
|
||||
const intptr_t size = is_trampoline ? data.trampoline_length
|
||||
: SizeInSnapshot(data.insns_->raw());
|
||||
profile_writer_->SetObjectTypeAndName(object_id, type, object_name);
|
||||
profile_writer_->AttributeBytesTo(object_id, size);
|
||||
// If the object is wrapped in an InstructionSection, then add an
|
||||
// element reference.
|
||||
if (bare_instruction_payloads) {
|
||||
profile_writer_->AttributeReferenceTo(
|
||||
instructions_section_id,
|
||||
{object_id, V8SnapshotProfileWriter::Reference::kElement,
|
||||
text_offset});
|
||||
}
|
||||
}
|
||||
|
||||
if (is_trampoline) {
|
||||
const auto start = reinterpret_cast<uword>(data.trampoline_bytes);
|
||||
const auto end = start + data.trampline_length;
|
||||
const auto end = start + data.trampoline_length;
|
||||
text_offset += WriteByteSequence(start, end);
|
||||
delete[] data.trampoline_bytes;
|
||||
data.trampoline_bytes = nullptr;
|
||||
|
@ -1123,7 +1189,6 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
const intptr_t instr_start = text_offset;
|
||||
|
||||
const Instructions& insns = *instructions_[i].insns_;
|
||||
AutoTraceImage(insns, 0, &this->instructions_blob_stream_);
|
||||
const uword payload_start = insns.PayloadStart();
|
||||
|
||||
ASSERT(Utils::IsAligned(payload_start, sizeof(compiler::target::uword)));
|
||||
|
@ -1190,13 +1255,16 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
const auto& code = *instructions_[i].code_;
|
||||
auto const virtual_address = segment_base + payload_stream_start;
|
||||
elf_dwarf_->AddCode(code, virtual_address);
|
||||
elf_->AddStaticSymbol(elf_->NextSectionIndex(),
|
||||
namer.AssemblyNameFor(i, code), virtual_address);
|
||||
elf_->AddStaticSymbol(elf_->NextSectionIndex(), object_name,
|
||||
virtual_address);
|
||||
}
|
||||
if (debug_dwarf_ != nullptr) {
|
||||
const auto& code = *instructions_[i].code_;
|
||||
auto const virtual_address = debug_segment_base + payload_stream_start;
|
||||
debug_dwarf_->AddCode(code, virtual_address);
|
||||
auto const elf = debug_dwarf_->elf();
|
||||
elf->AddStaticSymbol(elf->NextSectionIndex(), object_name,
|
||||
virtual_address);
|
||||
}
|
||||
|
||||
// Don't patch the relocation if we're not generating ELF. The regular blobs
|
||||
|
@ -1253,8 +1321,6 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
|
|||
ASSERT_EQUAL(instructions_blob_stream_.bytes_written(), image_size);
|
||||
|
||||
#ifdef DART_PRECOMPILER
|
||||
const char* instructions_symbol =
|
||||
vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions";
|
||||
if (elf_ != nullptr) {
|
||||
auto const segment_base2 =
|
||||
elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(),
|
||||
|
|
|
@ -149,8 +149,8 @@ struct ImageWriterCommand {
|
|||
|
||||
class ImageWriter : public ValueObject {
|
||||
public:
|
||||
explicit ImageWriter(Heap* heap);
|
||||
virtual ~ImageWriter() {}
|
||||
explicit ImageWriter(Thread* thread);
|
||||
virtual ~ImageWriter();
|
||||
|
||||
void ResetOffsets() {
|
||||
next_data_offset_ = Image::kHeaderSize;
|
||||
|
@ -166,12 +166,20 @@ class ImageWriter : public ValueObject {
|
|||
// [ImageWriterCommand]s.
|
||||
void PrepareForSerialization(GrowableArray<ImageWriterCommand>* commands);
|
||||
|
||||
bool IsROSpace() const {
|
||||
return offset_space_ == V8SnapshotProfileWriter::kVmData ||
|
||||
offset_space_ == V8SnapshotProfileWriter::kVmText ||
|
||||
offset_space_ == V8SnapshotProfileWriter::kIsolateData ||
|
||||
offset_space_ == V8SnapshotProfileWriter::kIsolateText;
|
||||
}
|
||||
int32_t GetTextOffsetFor(RawInstructions* instructions, RawCode* code);
|
||||
uint32_t GetDataOffsetFor(RawObject* raw_object);
|
||||
|
||||
void Write(WriteStream* clustered_stream, bool vm);
|
||||
intptr_t data_size() const { return next_data_offset_; }
|
||||
intptr_t text_size() const { return next_text_offset_; }
|
||||
intptr_t GetTextObjectCount() const;
|
||||
void GetTrampolineInfo(intptr_t* count, intptr_t* size) const;
|
||||
|
||||
void DumpStatistics();
|
||||
|
||||
|
@ -215,6 +223,10 @@ class ImageWriter : public ValueObject {
|
|||
marked_tags);
|
||||
}
|
||||
|
||||
// Returns nullptr if there is no profile writer.
|
||||
const char* ObjectTypeForProfile(const Object& object) const;
|
||||
static const char* TagObjectTypeAsReadOnly(Zone* zone, const char* type);
|
||||
|
||||
protected:
|
||||
void WriteROData(WriteStream* stream);
|
||||
virtual void WriteText(WriteStream* clustered_stream, bool vm) = 0;
|
||||
|
@ -230,16 +242,16 @@ class ImageWriter : public ValueObject {
|
|||
raw_code_(code),
|
||||
text_offset_(text_offset),
|
||||
trampoline_bytes(nullptr),
|
||||
trampline_length(0) {}
|
||||
trampoline_length(0) {}
|
||||
|
||||
InstructionsData(uint8_t* trampoline_bytes,
|
||||
intptr_t trampline_length,
|
||||
intptr_t trampoline_length,
|
||||
intptr_t text_offset)
|
||||
: raw_insns_(nullptr),
|
||||
raw_code_(nullptr),
|
||||
text_offset_(text_offset),
|
||||
trampoline_bytes(trampoline_bytes),
|
||||
trampline_length(trampline_length) {}
|
||||
trampoline_length(trampoline_length) {}
|
||||
|
||||
union {
|
||||
RawInstructions* raw_insns_;
|
||||
|
@ -252,7 +264,7 @@ class ImageWriter : public ValueObject {
|
|||
intptr_t text_offset_;
|
||||
|
||||
uint8_t* trampoline_bytes;
|
||||
intptr_t trampline_length;
|
||||
intptr_t trampoline_length;
|
||||
};
|
||||
|
||||
struct ObjectData {
|
||||
|
@ -273,9 +285,13 @@ class ImageWriter : public ValueObject {
|
|||
V8SnapshotProfileWriter::IdSpace offset_space_ =
|
||||
V8SnapshotProfileWriter::kSnapshot;
|
||||
V8SnapshotProfileWriter* profile_writer_ = nullptr;
|
||||
const char* const instructions_section_type_;
|
||||
const char* const instructions_type_;
|
||||
const char* const trampoline_type_;
|
||||
|
||||
template <class T>
|
||||
friend class TraceImageObjectScope;
|
||||
friend class SnapshotTextObjectNamer; // For InstructionsData.
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ImageWriter);
|
||||
|
@ -293,43 +309,34 @@ class TraceImageObjectScope {
|
|||
intptr_t section_offset,
|
||||
const T* stream,
|
||||
const Object& object)
|
||||
: writer_(writer),
|
||||
stream_(stream),
|
||||
: writer_(ASSERT_NOTNULL(writer)),
|
||||
stream_(ASSERT_NOTNULL(stream)),
|
||||
section_offset_(section_offset),
|
||||
start_offset_(stream_->Position() - section_offset) {
|
||||
if (writer_->profile_writer_ != nullptr) {
|
||||
Thread* thread = Thread::Current();
|
||||
REUSABLE_CLASS_HANDLESCOPE(thread);
|
||||
REUSABLE_STRING_HANDLESCOPE(thread);
|
||||
Class& klass = thread->ClassHandle();
|
||||
String& name = thread->StringHandle();
|
||||
klass = object.clazz();
|
||||
name = klass.UserVisibleName();
|
||||
ASSERT(writer_->offset_space_ != V8SnapshotProfileWriter::kSnapshot);
|
||||
writer_->profile_writer_->SetObjectTypeAndName(
|
||||
{writer_->offset_space_, start_offset_}, name.ToCString(), nullptr);
|
||||
}
|
||||
}
|
||||
start_offset_(stream_->Position() - section_offset),
|
||||
object_(object) {}
|
||||
|
||||
~TraceImageObjectScope() {
|
||||
if (writer_->profile_writer_ != nullptr) {
|
||||
ASSERT(writer_->offset_space_ != V8SnapshotProfileWriter::kSnapshot);
|
||||
writer_->profile_writer_->AttributeBytesTo(
|
||||
{writer_->offset_space_, start_offset_},
|
||||
stream_->Position() - section_offset_ - start_offset_);
|
||||
}
|
||||
if (writer_->profile_writer_ == nullptr) return;
|
||||
ASSERT(writer_->IsROSpace());
|
||||
writer_->profile_writer_->SetObjectTypeAndName(
|
||||
{writer_->offset_space_, start_offset_},
|
||||
writer_->ObjectTypeForProfile(object_), nullptr);
|
||||
writer_->profile_writer_->AttributeBytesTo(
|
||||
{writer_->offset_space_, start_offset_},
|
||||
stream_->Position() - section_offset_ - start_offset_);
|
||||
}
|
||||
|
||||
private:
|
||||
ImageWriter* writer_;
|
||||
const T* stream_;
|
||||
intptr_t section_offset_;
|
||||
intptr_t start_offset_;
|
||||
ImageWriter* const writer_;
|
||||
const T* const stream_;
|
||||
const intptr_t section_offset_;
|
||||
const intptr_t start_offset_;
|
||||
const Object& object_;
|
||||
};
|
||||
|
||||
class AssemblyCodeNamer {
|
||||
class SnapshotTextObjectNamer {
|
||||
public:
|
||||
explicit AssemblyCodeNamer(Zone* zone)
|
||||
explicit SnapshotTextObjectNamer(Zone* zone)
|
||||
: zone_(zone),
|
||||
owner_(Object::Handle(zone)),
|
||||
string_(String::Handle(zone)),
|
||||
|
@ -338,7 +345,9 @@ class AssemblyCodeNamer {
|
|||
|
||||
const char* StubNameForType(const AbstractType& type) const;
|
||||
|
||||
const char* AssemblyNameFor(intptr_t code_index, const Code& code);
|
||||
const char* SnapshotNameFor(intptr_t code_index, const Code& code);
|
||||
const char* SnapshotNameFor(intptr_t index,
|
||||
const ImageWriter::InstructionsData& data);
|
||||
|
||||
private:
|
||||
Zone* const zone_;
|
||||
|
|
Loading…
Reference in a new issue