Version 2.19.0-41.0.dev
Merge commit '3b8817e7fcd4abea2c8274543c101ad785788a20' into 'dev'
diff --git a/pkg/native_stack_traces/CHANGELOG.md b/pkg/native_stack_traces/CHANGELOG.md
index 39f1612..a1b47ce 100644
--- a/pkg/native_stack_traces/CHANGELOG.md
+++ b/pkg/native_stack_traces/CHANGELOG.md
@@ -1,7 +1,3 @@
-## 0.5.1
-
-- Exported more ELF utilities for use in Dart tests.
-
## 0.5.0
- Require Dart >= 2.17 (enhanced enum support)
diff --git a/pkg/native_stack_traces/lib/elf.dart b/pkg/native_stack_traces/lib/elf.dart
index 7c6e4bb..31272b1 100644
--- a/pkg/native_stack_traces/lib/elf.dart
+++ b/pkg/native_stack_traces/lib/elf.dart
@@ -8,12 +8,4 @@
isolateSymbolName,
vmDataSymbolName,
vmSymbolName;
-export 'src/elf.dart'
- show
- DynamicTable,
- DynamicTableTag,
- Elf,
- Section,
- Symbol,
- SymbolBinding,
- SymbolType;
+export 'src/elf.dart' show DynamicTable, DynamicTableTag, Elf, Section, Symbol;
diff --git a/pkg/native_stack_traces/lib/src/elf.dart b/pkg/native_stack_traces/lib/src/elf.dart
index 6b8bbbe..d8328eb 100644
--- a/pkg/native_stack_traces/lib/src/elf.dart
+++ b/pkg/native_stack_traces/lib/src/elf.dart
@@ -696,19 +696,16 @@
}
}
-/// An enumeration of recognized symbol binding values used by the ELF format.
enum SymbolBinding {
STB_LOCAL,
STB_GLOBAL,
STB_WEAK,
}
-/// An enumeration of recognized symbol types used by the ELF format.
enum SymbolType {
STT_NOTYPE,
STT_OBJECT,
STT_FUNC,
- STT_SECTION,
}
enum SymbolVisibility {
@@ -1009,17 +1006,6 @@
return null;
}
- /// Returns an iterable of the symbols in the dynamic symbol table(s).
- /// The ordering of the symbols is not guaranteed.
- Iterable<Symbol> get dynamicSymbols sync* {
- for (final section in namedSections('.dynsym')) {
- final dynsym = section as SymbolTable;
- for (final symbol in dynsym.values) {
- yield symbol;
- }
- }
- }
-
/// Reverse lookup of the static symbol that contains the given virtual
/// address. Returns null if no static symbol matching the address is found.
@override
@@ -1042,17 +1028,6 @@
return bestSym;
}
- /// Returns an iterable of the symbols in the static symbol table(s).
- /// The ordering of the symbols is not guaranteed.
- Iterable<Symbol> get staticSymbols sync* {
- for (final section in namedSections('.symtab')) {
- final symtab = section as SymbolTable;
- for (final symbol in symtab.values) {
- yield symbol;
- }
- }
- }
-
/// Creates an [Elf] from the data pointed to by [reader].
///
/// After succesful completion, the [endian] and [wordSize] fields of the
diff --git a/runtime/tests/vm/dart/readonly_data_symbols_test.dart b/runtime/tests/vm/dart/readonly_data_symbols_test.dart
deleted file mode 100644
index 3ccad9b..0000000
--- a/runtime/tests/vm/dart/readonly_data_symbols_test.dart
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test checks that gen_snapshot outputs static symbols for read-only
-// data objects.
-
-// OtherResources=use_save_debugging_info_flag_program.dart
-
-import "dart:async";
-import "dart:io";
-
-import 'package:expect/expect.dart';
-import 'package:native_stack_traces/elf.dart';
-import 'package:path/path.dart' as path;
-
-import 'use_flag_test_helper.dart';
-
-main(List<String> args) async {
- if (!isAOTRuntime) {
- return; // Running in JIT: AOT binaries not available.
- }
-
- if (Platform.isAndroid) {
- return; // SDK tree and dart_bootstrap not available on the test device.
- }
-
- // These are the tools we need to be available to run on a given platform:
- if (!await testExecutable(genSnapshot)) {
- throw "Cannot run test as $genSnapshot not available";
- }
- if (!await testExecutable(aotRuntime)) {
- throw "Cannot run test as $aotRuntime not available";
- }
- if (!File(platformDill).existsSync()) {
- throw "Cannot run test as $platformDill does not exist";
- }
-
- await withTempDir('readonly-symbols-flag-test', (String tempDir) async {
- final cwDir = path.dirname(Platform.script.toFilePath());
- final script =
- path.join(cwDir, 'use_save_debugging_info_flag_program.dart');
- final scriptDill = path.join(tempDir, 'flag_program.dill');
-
- // Compile script to Kernel IR.
- await run(genKernel, <String>[
- '--aot',
- '--platform=$platformDill',
- '-o',
- scriptDill,
- script,
- ]);
-
- final scriptSnapshot = path.join(tempDir, 'dwarf.so');
- final scriptDebuggingInfo = path.join(tempDir, 'debug_info.so');
- await run(genSnapshot, <String>[
- '--dwarf-stack-traces-mode',
- '--save-debugging-info=$scriptDebuggingInfo',
- '--snapshot-kind=app-aot-elf',
- '--elf=$scriptSnapshot',
- scriptDill,
- ]);
-
- checkElf(scriptSnapshot);
- checkElf(scriptDebuggingInfo);
- });
-}
-
-void checkElf(String filename) {
- // Check that the static symbol table contains entries that are not in the
- // dynamic symbol table, have STB_LOCAL binding, and are of type STT_OBJECT.
- final elf = Elf.fromFile(filename);
- Expect.isNotNull(elf);
- final dynamicSymbols = elf!.dynamicSymbols.toList();
- for (final symbol in dynamicSymbols) {
- // All symbol tables have an initial entry with zero-valued fields.
- if (symbol.name == '') {
- Expect.equals(SymbolBinding.STB_LOCAL, symbol.bind);
- Expect.equals(SymbolType.STT_NOTYPE, symbol.type);
- Expect.equals(0, symbol.value);
- } else {
- Expect.equals(SymbolBinding.STB_GLOBAL, symbol.bind);
- Expect.equals(SymbolType.STT_OBJECT, symbol.type);
- Expect.isTrue(symbol.name.startsWith('_kDart'),
- 'unexpected symbol name ${symbol.name}');
- }
- }
- final onlyStaticSymbols = elf.staticSymbols
- .where((s1) => !dynamicSymbols.any((s2) => s1.name == s2.name));
- Expect.isNotEmpty(onlyStaticSymbols, 'no static-only symbols');
- final objectSymbols =
- onlyStaticSymbols.where((s) => s.type == SymbolType.STT_OBJECT);
- Expect.isNotEmpty(objectSymbols, 'no static-only object symbols');
- for (final symbol in objectSymbols) {
- // Currently we only write local object symbols.
- Expect.equals(SymbolBinding.STB_LOCAL, symbol.bind);
- // All object symbols are prefixed with the type of the C++ object.
- final objectType = symbol.name.substring(0, symbol.name.indexOf('_'));
- switch (objectType) {
- // Used for entries in the non-clustered portion of the read-only data
- // section that don't correspond to a specific Dart object.
- case 'RawBytes':
- // Currently the only types of objects written to the non-clustered
- // portion of the read-only data section.
- case 'OneByteString':
- case 'TwoByteString':
- case 'CodeSourceMap':
- case 'PcDescriptors':
- case 'CompressedStackMaps':
- break;
- default:
- Expect.fail('unexpected object type $objectType');
- }
- }
-}
diff --git a/runtime/tests/vm/dart_2/readonly_data_symbols_test.dart b/runtime/tests/vm/dart_2/readonly_data_symbols_test.dart
deleted file mode 100644
index c646840..0000000
--- a/runtime/tests/vm/dart_2/readonly_data_symbols_test.dart
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.9
-
-// This test checks that gen_snapshot outputs static symbols for read-only data
-// objects.
-
-// OtherResources=use_save_debugging_info_flag_program.dart
-
-import "dart:async";
-import "dart:io";
-
-import 'package:expect/expect.dart';
-import 'package:native_stack_traces/elf.dart';
-import 'package:path/path.dart' as path;
-
-import 'use_flag_test_helper.dart';
-
-main(List<String> args) async {
- if (!isAOTRuntime) {
- return; // Running in JIT: AOT binaries not available.
- }
-
- if (Platform.isAndroid) {
- return; // SDK tree and dart_bootstrap not available on the test device.
- }
-
- // These are the tools we need to be available to run on a given platform:
- if (!await testExecutable(genSnapshot)) {
- throw "Cannot run test as $genSnapshot not available";
- }
- if (!await testExecutable(aotRuntime)) {
- throw "Cannot run test as $aotRuntime not available";
- }
- if (!File(platformDill).existsSync()) {
- throw "Cannot run test as $platformDill does not exist";
- }
-
- await withTempDir('readonly-symbols-flag-test', (String tempDir) async {
- final cwDir = path.dirname(Platform.script.toFilePath());
- final script =
- path.join(cwDir, 'use_save_debugging_info_flag_program.dart');
- final scriptDill = path.join(tempDir, 'flag_program.dill');
-
- // Compile script to Kernel IR.
- await run(genKernel, <String>[
- '--aot',
- '--platform=$platformDill',
- '-o',
- scriptDill,
- script,
- ]);
-
- final scriptSnapshot = path.join(tempDir, 'dwarf.so');
- final scriptDebuggingInfo = path.join(tempDir, 'debug_info.so');
- await run(genSnapshot, <String>[
- '--dwarf-stack-traces-mode',
- '--save-debugging-info=$scriptDebuggingInfo',
- '--snapshot-kind=app-aot-elf',
- '--elf=$scriptSnapshot',
- scriptDill,
- ]);
-
- checkElf(scriptSnapshot);
- checkElf(scriptDebuggingInfo);
- });
-}
-
-void checkElf(String filename) {
- // Check that the static symbol table contains entries that are not in the
- // dynamic symbol table, have STB_LOCAL binding, and are of type STT_OBJECT.
- final elf = Elf.fromFile(filename);
- Expect.isNotNull(elf);
- final dynamicSymbols = elf.dynamicSymbols.toList();
- for (final symbol in dynamicSymbols) {
- // All symbol tables have an initial entry with zero-valued fields.
- if (symbol.name == '') {
- Expect.equals(SymbolBinding.STB_LOCAL, symbol.bind);
- Expect.equals(SymbolType.STT_NOTYPE, symbol.type);
- Expect.equals(0, symbol.value);
- } else {
- Expect.equals(SymbolBinding.STB_GLOBAL, symbol.bind);
- Expect.equals(SymbolType.STT_OBJECT, symbol.type);
- Expect.isTrue(symbol.name.startsWith('_kDart'),
- 'unexpected symbol name ${symbol.name}');
- }
- }
- final onlyStaticSymbols = elf.staticSymbols
- .where((s1) => !dynamicSymbols.any((s2) => s1.name == s2.name));
- Expect.isNotEmpty(onlyStaticSymbols, 'no static-only symbols');
- final objectSymbols =
- onlyStaticSymbols.where((s) => s.type == SymbolType.STT_OBJECT);
- Expect.isNotEmpty(objectSymbols, 'no static-only object symbols');
- for (final symbol in objectSymbols) {
- // Currently we only write local object symbols.
- Expect.equals(SymbolBinding.STB_LOCAL, symbol.bind);
- // All object symbols are prefixed with the type of the C++ object.
- final objectType = symbol.name.substring(0, symbol.name.indexOf('_'));
- switch (objectType) {
- // Used for entries in the non-clustered portion of the read-only data
- // section that don't correspond to a specific Dart object.
- case 'RawBytes':
- // Currently the only types of objects written to the non-clustered
- // portion of the read-only data section.
- case 'OneByteString':
- case 'TwoByteString':
- case 'CodeSourceMap':
- case 'PcDescriptors':
- case 'CompressedStackMaps':
- break;
- default:
- Expect.fail('unexpected object type $objectType');
- }
- }
-}
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc
index 14cc87c..ea36ec5 100644
--- a/runtime/vm/app_snapshot.cc
+++ b/runtime/vm/app_snapshot.cc
@@ -7288,11 +7288,7 @@
}
uint32_t Serializer::GetDataOffset(ObjectPtr object) const {
-#if defined(SNAPSHOT_BACKTRACE)
- return image_writer_->GetDataOffsetFor(object, ParentOf(object));
-#else
return image_writer_->GetDataOffsetFor(object);
-#endif
}
intptr_t Serializer::GetDataSize() const {
@@ -7397,16 +7393,7 @@
}
#if defined(SNAPSHOT_BACKTRACE)
-ObjectPtr Serializer::ParentOf(ObjectPtr object) const {
- for (intptr_t i = 0; i < parent_pairs_.length(); i += 2) {
- if (parent_pairs_[i]->ptr() == object) {
- return parent_pairs_[i + 1]->ptr();
- }
- }
- return Object::null();
-}
-
-ObjectPtr Serializer::ParentOf(const Object& object) const {
+ObjectPtr Serializer::ParentOf(const Object& object) {
for (intptr_t i = 0; i < parent_pairs_.length(); i += 2) {
if (parent_pairs_[i]->ptr() == object.ptr()) {
return parent_pairs_[i + 1]->ptr();
diff --git a/runtime/vm/app_snapshot.h b/runtime/vm/app_snapshot.h
index 3445cb4..922c8ac 100644
--- a/runtime/vm/app_snapshot.h
+++ b/runtime/vm/app_snapshot.h
@@ -19,6 +19,10 @@
#include "vm/snapshot.h"
#include "vm/version.h"
+#if defined(DEBUG)
+#define SNAPSHOT_BACKTRACE
+#endif
+
namespace dart {
// For full snapshots, we use a clustered snapshot format that trades longer
@@ -240,8 +244,7 @@
void UnexpectedObject(ObjectPtr object, const char* message);
#if defined(SNAPSHOT_BACKTRACE)
- ObjectPtr ParentOf(ObjectPtr object) const;
- ObjectPtr ParentOf(const Object& object) const;
+ ObjectPtr ParentOf(const Object& object);
#endif
SerializationCluster* NewClusterForClass(intptr_t cid, bool is_canonical);
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 508fb3e4..8115931 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -179,9 +179,6 @@
next_text_offset_(0),
objects_(),
instructions_(),
-#if defined(DART_PRECOMPILER)
- namer_(t->zone()),
-#endif
image_type_(TagObjectTypeAsReadOnly(zone_, "Image")),
instructions_section_type_(
TagObjectTypeAsReadOnly(zone_, "InstructionsSection")),
@@ -289,20 +286,11 @@
}
}
-#if defined(SNAPSHOT_BACKTRACE)
-uint32_t ImageWriter::GetDataOffsetFor(ObjectPtr raw_object,
- ObjectPtr raw_parent) {
-#else
uint32_t ImageWriter::GetDataOffsetFor(ObjectPtr raw_object) {
-#endif
const intptr_t snap_size = SizeInSnapshot(raw_object);
const intptr_t offset = next_data_offset_;
next_data_offset_ += snap_size;
-#if defined(SNAPSHOT_BACKTRACE)
- objects_.Add(ObjectData(raw_object, raw_parent));
-#else
objects_.Add(ObjectData(raw_object));
-#endif
return offset;
}
@@ -467,11 +455,8 @@
heap->SetObjectId(data.insns_->ptr(), 0);
}
for (auto& data : objects_) {
- if (data.is_object()) {
+ if (data.is_object) {
data.obj = &Object::Handle(zone_, data.raw_obj);
-#if defined(SNAPSHOT_BACKTRACE)
- data.parent = &Object::Handle(zone_, data.raw_parent);
-#endif
}
}
@@ -479,14 +464,11 @@
// to string objects. String is used for simplicity as a bit container,
// can't use TypedData because it has an internal pointer (data_) field.
for (auto& data : objects_) {
- if (!data.is_object()) {
+ if (!data.is_object) {
const auto bytes = data.bytes;
data.obj = &Object::Handle(
zone_, OneByteString::New(bytes.buf, bytes.length, Heap::kOld));
-#if defined(SNAPSHOT_BACKTRACE)
- data.parent = &Object::null_object();
-#endif
- data.set_is_object(true);
+ data.is_object = true;
String::Cast(*data.obj).Hash();
free(bytes.buf);
}
@@ -507,8 +489,13 @@
}
void ImageWriter::WriteROData(NonStreamingWriteStream* stream, bool vm) {
- ASSERT(Utils::IsAligned(stream->Position(), kRODataAlignment));
+#if defined(DART_PRECOMPILER)
+ const intptr_t start_position = stream->Position();
+#endif
+ stream->Align(ImageWriter::kRODataAlignment);
+
// Heap page starts here.
+
intptr_t section_start = stream->Position();
stream->WriteWord(next_data_offset_); // Data length.
@@ -518,20 +505,20 @@
ASSERT_EQUAL(stream->Position() - section_start, Image::kHeaderSize);
#if defined(DART_PRECOMPILER)
if (profile_writer_ != nullptr) {
- // Attribute the Image header to the artificial root.
+ const intptr_t end_position = stream->Position();
profile_writer_->AttributeBytesTo(
- V8SnapshotProfileWriter::kArtificialRootId, Image::kHeaderSize);
+ V8SnapshotProfileWriter::kArtificialRootId,
+ end_position - start_position);
}
#endif
// Heap page objects start here.
for (auto entry : objects_) {
- ASSERT(entry.is_object());
+ ASSERT(entry.is_object);
const Object& obj = *entry.obj;
#if defined(DART_PRECOMPILER)
AutoTraceImage(obj, section_start, stream);
- const char* object_name = namer_.SnapshotNameFor(entry);
#endif
auto const object_start = stream->Position();
@@ -581,9 +568,6 @@
}
stream->Align(compiler::target::ObjectAlignment::kObjectAlignment);
ASSERT_EQUAL(stream->Position() - object_start, SizeInSnapshot(obj));
-#if defined(DART_PRECOMPILER)
- AddDataSymbol(object_name, object_start, stream->Position() - object_start);
-#endif
}
}
@@ -788,6 +772,7 @@
#if defined(DART_PRECOMPILER)
PcDescriptors& descriptors = PcDescriptors::Handle(zone_);
+ SnapshotTextObjectNamer namer(zone_);
#endif
ASSERT(offset_space_ != IdSpace::kSnapshot);
@@ -797,7 +782,10 @@
ASSERT_EQUAL(data.text_offset_, text_offset);
#if defined(DART_PRECOMPILER)
- const char* object_name = namer_.SnapshotNameFor(data);
+ // We won't add trampolines as symbols, so their name need not be unique
+ // across different WriteText() calls.
+ const char* object_name = namer.SnapshotNameFor(
+ is_trampoline ? i : unique_symbol_counter_++, data);
if (profile_writer_ != nullptr) {
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
@@ -1118,7 +1106,7 @@
}
}
-static void AddAssemblerIdentifier(BaseTextBuffer* printer, const char* label) {
+static void AddAssemblerIdentifier(ZoneTextBuffer* printer, const char* label) {
ASSERT(label[0] != '.');
if (label[0] == 'L' && printer->length() == 0) {
// Assembler treats labels starting with `L` as local which can cause
@@ -1171,89 +1159,47 @@
}
}
-void ImageWriter::SnapshotTextObjectNamer::AddNonUniqueNameFor(
- BaseTextBuffer* buffer,
- const Object& object) {
- if (object.IsCode()) {
- const Code& code = Code::Cast(object);
- owner_ = WeakSerializationReference::Unwrap(code.owner());
- if (owner_.IsNull()) {
- buffer->AddString("Stub_");
- insns_ = code.instructions();
- const char* name = StubCode::NameOfStub(insns_.EntryPoint());
- ASSERT(name != nullptr);
- buffer->AddString(name);
- } else {
- if (owner_.IsClass()) {
- buffer->AddString("AllocationStub_");
- } else if (!owner_.IsAbstractType() && !owner_.IsFunction()) {
- // Double-check that we didn't get an invalid owner for the Code object.
- UNREACHABLE();
- }
- AddNonUniqueNameFor(buffer, owner_);
- }
- } else if (object.IsClass()) {
- const char* name = Class::Cast(object).ScrubbedNameCString();
- AddAssemblerIdentifier(buffer, name);
- } else if (object.IsAbstractType()) {
- namer_.WriteStubNameForTypeTo(buffer, AbstractType::Cast(object));
- } else if (object.IsFunction()) {
- const char* name = Function::Cast(object).QualifiedScrubbedNameCString();
- AddAssemblerIdentifier(buffer, name);
- } else if (object.IsCompressedStackMaps()) {
- buffer->AddString("CompressedStackMaps");
- } else if (object.IsPcDescriptors()) {
- buffer->AddString("PcDescriptors");
- } else if (object.IsCodeSourceMap()) {
- buffer->AddString("CodeSourceMap");
- } else if (object.IsString()) {
- const String& str = String::Cast(object);
- if (str.IsOneByteString()) {
- buffer->AddString("OneByteString");
- } else if (str.IsTwoByteString()) {
- buffer->AddString("TwoByteString");
- }
+const char* SnapshotTextObjectNamer::SnapshotNameFor(intptr_t code_index,
+ const Code& code) {
+ ASSERT(!code.IsNull());
+ owner_ = code.owner();
+ if (owner_.IsNull()) {
+ insns_ = code.instructions();
+ const char* name = StubCode::NameOfStub(insns_.EntryPoint());
+ ASSERT(name != nullptr);
+ return OS::SCreate(zone_, "Stub_%s", name);
+ }
+ // The weak reference to the Code's owner should never have been removed via
+ // an intermediate serialization, since WSRs are only introduced during
+ // precompilation.
+ owner_ = WeakSerializationReference::Unwrap(owner_);
+ ASSERT(!owner_.IsNull());
+ ZoneTextBuffer printer(zone_);
+ if (owner_.IsClass()) {
+ const char* name = Class::Cast(owner_).ScrubbedNameCString();
+ printer.AddString("AllocationStub_");
+ AddAssemblerIdentifier(&printer, name);
+ } else if (owner_.IsAbstractType()) {
+ const char* name = namer_.StubNameForType(AbstractType::Cast(owner_));
+ printer.AddString(name);
+ } else if (owner_.IsFunction()) {
+ const char* name = Function::Cast(owner_).QualifiedScrubbedNameCString();
+ AddAssemblerIdentifier(&printer, name);
} else {
UNREACHABLE();
}
+
+ printer.Printf("_%" Pd, code_index);
+ return printer.buffer();
}
-const char* ImageWriter::SnapshotTextObjectNamer::SnapshotNameFor(
- const InstructionsData& data) {
- ZoneTextBuffer printer(zone_);
+const char* SnapshotTextObjectNamer::SnapshotNameFor(
+ intptr_t index,
+ const ImageWriter::InstructionsData& data) {
if (data.trampoline_bytes != nullptr) {
- printer.AddString("Trampoline");
- } else {
- AddNonUniqueNameFor(&printer, *data.code_);
+ return OS::SCreate(zone_, "Trampoline_%" Pd "", index);
}
- printer.Printf("_%" Pd, nonce_++);
- return printer.buffer();
-}
-
-const char* ImageWriter::SnapshotTextObjectNamer::SnapshotNameFor(
- const ObjectData& data) {
- ASSERT(data.is_object());
- ZoneTextBuffer printer(zone_);
- if (data.is_original_object()) {
- const Object& obj = *data.obj;
- AddNonUniqueNameFor(&printer, obj);
-#if defined(SNAPSHOT_BACKTRACE)
- // It's less useful knowing the parent of a String than other read-only
- // data objects, and this avoids us having to handle other classes
- // in AddNonUniqueNameFor.
- if (!obj.IsString()) {
- const Object& parent = *data.parent;
- if (!parent.IsNull()) {
- printer.AddString("_");
- AddNonUniqueNameFor(&printer, parent);
- }
- }
-#endif
- } else {
- printer.AddString("RawBytes");
- }
- printer.Printf("_%" Pd, nonce_++);
- return printer.buffer();
+ return SnapshotNameFor(index, *data.code_);
}
void AssemblyImageWriter::WriteBss(bool vm) {
@@ -1269,35 +1215,12 @@
void AssemblyImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
bool vm) {
+ ImageWriter::WriteROData(clustered_stream, vm);
if (!EnterSection(ProgramSection::Data, vm, ImageWriter::kRODataAlignment)) {
return;
}
- // The clustered stream already has some data on it from the serializer, so
- // make sure that the read-only objects start at the appropriate alignment
- // within the stream, as we'll write the entire clustered stream to the
- // assembly output (which was aligned in EnterSection).
- const intptr_t start_position = clustered_stream->Position();
- clustered_stream->Align(ImageWriter::kRODataAlignment);
- if (profile_writer_ != nullptr) {
- // Attribute any padding needed to the artificial root.
- const intptr_t padding = clustered_stream->Position() - start_position;
- profile_writer_->AttributeBytesTo(
- V8SnapshotProfileWriter::kArtificialRootId, padding);
- }
- // First write the read-only data objects to the clustered stream.
- ImageWriter::WriteROData(clustered_stream, vm);
- // Next, write the bytes of the clustered stream (along with any symbols
- // if appropriate) to the assembly output.
- const uint8_t* bytes = clustered_stream->buffer();
- const intptr_t len = clustered_stream->bytes_written();
- intptr_t last_position = 0;
- for (const auto& symbol : *current_symbols_) {
- WriteBytes(bytes + last_position, symbol.offset - last_position);
- assembly_stream_->Printf("%s:\n", symbol.name);
- last_position = symbol.offset;
- }
- WriteBytes(bytes + last_position, len - last_position);
- ExitSection(ProgramSection::Data, vm, len);
+ WriteBytes(clustered_stream->buffer(), clustered_stream->bytes_written());
+ ExitSection(ProgramSection::Data, vm, clustered_stream->bytes_written());
}
bool AssemblyImageWriter::EnterSection(ProgramSection section,
@@ -1317,14 +1240,10 @@
global_symbol = true;
break;
case ProgramSection::Data:
- // We create a SymbolData array even if there is no debug_elf_ because we
- // may be writing RO data symbols, and RO data is written in two steps:
- // 1. Serializing the read-only data objects to the clustered stream
- // 2. Writing the bytes of the clustered stream to the assembly output.
- // Thus, we'll need to interleave the symbols with the cluster bytes
- // during step 2.
- current_symbols_ =
- new (zone_) ZoneGrowableArray<Elf::SymbolData>(zone_, 0);
+ if (debug_elf_ != nullptr) {
+ current_symbols_ =
+ new (zone_) ZoneGrowableArray<Elf::SymbolData>(zone_, 0);
+ }
#if defined(DART_TARGET_OS_LINUX) || defined(DART_TARGET_OS_ANDROID) || \
defined(DART_TARGET_OS_FUCHSIA)
assembly_stream_->WriteString(".section .rodata\n");
@@ -1462,12 +1381,6 @@
assembly_stream_->Printf("%s:\n", symbol);
}
-void AssemblyImageWriter::AddDataSymbol(const char* symbol,
- intptr_t offset,
- size_t size) {
- current_symbols_->Add({symbol, elf::STT_OBJECT, offset, size});
-}
-
void AssemblyImageWriter::FrameUnwindPrologue() {
// Creates DWARF's .debug_frame
// CFI = Call frame information
@@ -1591,22 +1504,11 @@
void BlobImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
bool vm) {
-#if defined(DART_PRECOMPILER)
- const intptr_t start_position = clustered_stream->Position();
-#endif
- current_section_stream_ = ASSERT_NOTNULL(clustered_stream);
+ ImageWriter::WriteROData(clustered_stream, vm);
+ current_section_stream_ = clustered_stream;
if (!EnterSection(ProgramSection::Data, vm, ImageWriter::kRODataAlignment)) {
return;
}
-#if defined(DART_PRECOMPILER)
- if (profile_writer_ != nullptr) {
- // Attribute any padding needed to the artificial root.
- const intptr_t padding = clustered_stream->Position() - start_position;
- profile_writer_->AttributeBytesTo(
- V8SnapshotProfileWriter::kArtificialRootId, padding);
- }
-#endif
- ImageWriter::WriteROData(clustered_stream, vm);
ExitSection(ProgramSection::Data, vm, clustered_stream->bytes_written());
}
@@ -1618,6 +1520,7 @@
ASSERT(current_relocations_ == nullptr);
ASSERT(current_symbols_ == nullptr);
#endif
+ // For now, we set current_section_stream_ in ::WriteData.
ASSERT(section == ProgramSection::Data || current_section_stream_ == nullptr);
ASSERT(current_section_symbol_ == nullptr);
switch (section) {
@@ -1632,8 +1535,6 @@
#endif
break;
case ProgramSection::Data:
- // The stream to use is passed into WriteROData and set there.
- ASSERT(current_section_stream_ != nullptr);
#if defined(DART_PRECOMPILER)
current_relocations_ =
new (zone_) ZoneGrowableArray<Elf::Relocation>(zone_, 0);
@@ -1713,12 +1614,6 @@
debug_elf_->dwarf()->AddCode(code, symbol);
}
}
-
-void BlobImageWriter::AddDataSymbol(const char* symbol,
- intptr_t offset,
- size_t size) {
- current_symbols_->Add({symbol, elf::STT_OBJECT, offset, size});
-}
#endif // defined(DART_PRECOMPILER)
#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index c1ce151..730b861 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -22,10 +22,6 @@
#include "vm/type_testing_stubs.h"
#include "vm/v8_snapshot_writer.h"
-#if defined(DEBUG)
-#define SNAPSHOT_BACKTRACE
-#endif
-
namespace dart {
// Forward declarations.
@@ -274,11 +270,7 @@
offset_space_ == IdSpace::kIsolateText;
}
int32_t GetTextOffsetFor(InstructionsPtr instructions, CodePtr code);
-#if defined(SNAPSHOT_BACKTRACE)
- uint32_t GetDataOffsetFor(ObjectPtr raw_object, ObjectPtr raw_parent);
-#else
uint32_t GetDataOffsetFor(ObjectPtr raw_object);
-#endif
uint32_t AddBytesToData(uint8_t* bytes, intptr_t length);
@@ -364,27 +356,10 @@
};
struct ObjectData {
-#if defined(SNAPSHOT_BACKTRACE)
- explicit ObjectData(ObjectPtr raw_obj, ObjectPtr raw_parent)
- : raw_obj(raw_obj),
- raw_parent(raw_parent),
- flags(IsObjectField::encode(true) |
- IsOriginalObjectField::encode(true)) {}
- ObjectData(uint8_t* buf, intptr_t length)
- : bytes({buf, length}),
- raw_parent(Object::null()),
- flags(IsObjectField::encode(false) |
- IsOriginalObjectField::encode(false)) {}
-#else
explicit ObjectData(ObjectPtr raw_obj)
- : raw_obj(raw_obj),
- flags(IsObjectField::encode(true) |
- IsOriginalObjectField::encode(true)) {}
+ : raw_obj(raw_obj), is_object(true) {}
ObjectData(uint8_t* buf, intptr_t length)
- : bytes({buf, length}),
- flags(IsObjectField::encode(false) |
- IsOriginalObjectField::encode(false)) {}
-#endif
+ : bytes({buf, length}), is_object(false) {}
union {
struct {
@@ -394,26 +369,7 @@
ObjectPtr raw_obj;
const Object* obj;
};
-#if defined(SNAPSHOT_BACKTRACE)
- union {
- ObjectPtr raw_parent;
- const Object* parent;
- };
-#endif
- uint8_t flags;
-
- bool is_object() const { return IsObjectField::decode(flags); }
- bool is_original_object() const {
- return IsOriginalObjectField::decode(flags);
- }
-
- void set_is_object(bool value) {
- flags = IsObjectField::update(value, flags);
- }
-
- using IsObjectField = BitField<uint8_t, bool, 0, 1>;
- using IsOriginalObjectField =
- BitField<uint8_t, bool, IsObjectField::kNextBit, 1>;
+ bool is_object;
};
// Methods abstracting out the particulars of the underlying concrete writer.
@@ -459,10 +415,6 @@
virtual void AddCodeSymbol(const Code& code,
const char* symbol,
intptr_t section_offset) = 0;
- // Creates a static symbol for a read-only data object when appropriate.
- virtual void AddDataSymbol(const char* symbol,
- intptr_t section_offset,
- size_t size) = 0;
// Overloaded convenience versions of the above virtual methods.
@@ -490,47 +442,6 @@
GrowableArray<ObjectData> objects_;
GrowableArray<InstructionsData> instructions_;
-#if defined(DART_PRECOMPILER)
- class SnapshotTextObjectNamer : ValueObject {
- public:
- explicit SnapshotTextObjectNamer(Zone* zone)
- : zone_(ASSERT_NOTNULL(zone)),
- owner_(Object::Handle(zone)),
- string_(String::Handle(zone)),
- insns_(Instructions::Handle(zone)),
- store_(IsolateGroup::Current()->object_store()) {}
-
- const char* StubNameForType(const AbstractType& type) const;
-
- // Returns a unique assembly-safe name for text data to use in symbols.
- // Assumes that code in the InstructionsData has been allocated a handle.
- const char* SnapshotNameFor(const InstructionsData& data);
- // Returns a unique assembly-safe name for read-only data to use in symbols.
- // Assumes that the ObjectData has already been converted to object handles.
- const char* SnapshotNameFor(const ObjectData& data);
-
- private:
- // Returns a unique assembly-safe name for the given code or read-only
- // data object for use in symbols.
- const char* SnapshotNameFor(const Object& object);
- // Adds a non-unique assembly-safe name for the given object to the given
- // buffer.
- void AddNonUniqueNameFor(BaseTextBuffer* buffer, const Object& object);
-
- Zone* const zone_;
- Object& owner_;
- String& string_;
- Instructions& insns_;
- ObjectStore* const store_;
- TypeTestingStubNamer namer_;
- intptr_t nonce_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(SnapshotTextObjectNamer);
- };
-
- SnapshotTextObjectNamer namer_;
-#endif
-
IdSpace offset_space_ = IdSpace::kSnapshot;
V8SnapshotProfileWriter* profile_writer_ = nullptr;
const char* const image_type_;
@@ -538,8 +449,12 @@
const char* const instructions_type_;
const char* const trampoline_type_;
+ // Used to make sure Code symbols are unique across text sections.
+ intptr_t unique_symbol_counter_ = 0;
+
template <class T>
friend class TraceImageObjectScope;
+ friend class SnapshotTextObjectNamer; // For InstructionsData.
private:
static intptr_t SizeInSnapshotForBytes(intptr_t length);
@@ -588,6 +503,32 @@
DISALLOW_COPY_AND_ASSIGN(TraceImageObjectScope);
};
+class SnapshotTextObjectNamer : ValueObject {
+ public:
+ explicit SnapshotTextObjectNamer(Zone* zone)
+ : zone_(ASSERT_NOTNULL(zone)),
+ owner_(Object::Handle(zone)),
+ string_(String::Handle(zone)),
+ insns_(Instructions::Handle(zone)),
+ store_(IsolateGroup::Current()->object_store()) {}
+
+ const char* StubNameForType(const AbstractType& type) const;
+
+ const char* SnapshotNameFor(intptr_t code_index, const Code& code);
+ const char* SnapshotNameFor(intptr_t index,
+ const ImageWriter::InstructionsData& data);
+
+ private:
+ Zone* const zone_;
+ Object& owner_;
+ String& string_;
+ Instructions& insns_;
+ ObjectStore* const store_;
+ TypeTestingStubNamer namer_;
+
+ DISALLOW_COPY_AND_ASSIGN(SnapshotTextObjectNamer);
+};
+
class AssemblyImageWriter : public ImageWriter {
public:
AssemblyImageWriter(Thread* thread,
@@ -622,7 +563,6 @@
virtual void AddCodeSymbol(const Code& code,
const char* symbol,
intptr_t offset);
- virtual void AddDataSymbol(const char* symbol, intptr_t offset, size_t size);
BaseWriteStream* const assembly_stream_;
Dwarf* const assembly_dwarf_;
@@ -631,8 +571,8 @@
// Used in Relocation to output "(.)" for relocations involving the current
// section position and creating local symbols in AddCodeSymbol.
const char* current_section_symbol_ = nullptr;
- // Used for creating local symbols for code and data objects in the
- // debugging info, if separately written.
+ // Used for creating local symbols for code objects in the debugging info,
+ // if separately written.
ZoneGrowableArray<Elf::SymbolData>* current_symbols_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(AssemblyImageWriter);
@@ -676,7 +616,6 @@
virtual void AddCodeSymbol(const Code& code,
const char* symbol,
intptr_t offset);
- virtual void AddDataSymbol(const char* symbol, intptr_t offset, size_t size);
// Set on section entrance to a new array containing the relocations for the
// current section.
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index a62a5e4..41ac9d1 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -14,7 +14,6 @@
#include "vm/stub_code.h"
#include "vm/timeline.h"
#include "vm/type_testing_stubs.h"
-#include "vm/zone_text_buffer.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/backend/flow_graph_compiler.h"
@@ -33,60 +32,57 @@
const char* TypeTestingStubNamer::StubNameForType(
const AbstractType& type) const {
- ZoneTextBuffer buffer(Thread::Current()->zone());
- WriteStubNameForTypeTo(&buffer, type);
- return buffer.buffer();
+ Zone* Z = Thread::Current()->zone();
+ return OS::SCreate(Z, "TypeTestingStub_%s", StringifyType(type));
}
-void TypeTestingStubNamer::WriteStubNameForTypeTo(
- BaseTextBuffer* buffer,
+const char* TypeTestingStubNamer::StringifyType(
const AbstractType& type) const {
- buffer->AddString("TypeTestingStub_");
- StringifyTypeTo(buffer, type);
-}
-
-void TypeTestingStubNamer::StringifyTypeTo(BaseTextBuffer* buffer,
- const AbstractType& type) const {
NoSafepointScope no_safepoint;
+ Zone* Z = Thread::Current()->zone();
if (type.IsType()) {
const intptr_t cid = Type::Cast(type).type_class_id();
ClassTable* class_table = IsolateGroup::Current()->class_table();
klass_ = class_table->At(cid);
ASSERT(!klass_.IsNull());
+ const char* curl = "";
lib_ = klass_.library();
if (!lib_.IsNull()) {
string_ = lib_.url();
- buffer->AddString(string_.ToCString());
+ curl = OS::SCreate(Z, "%s_", string_.ToCString());
} else {
- buffer->Printf("nolib%" Pd "_", nonce_++);
+ static std::atomic<intptr_t> counter = 0;
+ curl = OS::SCreate(Z, "nolib%" Pd "_", counter++);
}
- buffer->AddString("_");
- buffer->AddString(klass_.ScrubbedNameCString());
+ const char* concatenated = AssemblerSafeName(
+ OS::SCreate(Z, "%s_%s", curl, klass_.ScrubbedNameCString()));
const intptr_t type_parameters = klass_.NumTypeParameters();
- auto& type_arguments = TypeArguments::Handle(type.arguments());
- if (!type_arguments.IsNull() && type_parameters > 0) {
+ auto& type_arguments = TypeArguments::Handle();
+ if (type.arguments() != TypeArguments::null() && type_parameters > 0) {
type_arguments = type.arguments();
ASSERT(type_arguments.Length() >= type_parameters);
const intptr_t length = type_arguments.Length();
for (intptr_t i = 0; i < type_parameters; ++i) {
type_ = type_arguments.TypeAt(length - type_parameters + i);
- buffer->AddString("__");
- StringifyTypeTo(buffer, type_);
+ concatenated =
+ OS::SCreate(Z, "%s__%s", concatenated, StringifyType(type_));
}
}
+
+ return concatenated;
} else if (type.IsTypeParameter()) {
- buffer->AddString(TypeParameter::Cast(type).CanonicalNameCString());
+ return AssemblerSafeName(
+ OS::SCreate(Z, "%s", TypeParameter::Cast(type).CanonicalNameCString()));
} else {
- buffer->AddString(type.ToCString());
+ return AssemblerSafeName(OS::SCreate(Z, "%s", type.ToCString()));
}
- MakeNameAssemblerSafe(buffer);
}
-void TypeTestingStubNamer::MakeNameAssemblerSafe(BaseTextBuffer* buffer) {
- char* cursor = buffer->buffer();
+const char* TypeTestingStubNamer::AssemblerSafeName(char* cname) {
+ char* cursor = cname;
while (*cursor != '\0') {
char c = *cursor;
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
@@ -95,6 +91,7 @@
}
cursor++;
}
+ return cname;
}
CodePtr TypeTestingStubGenerator::DefaultCodeForType(
diff --git a/runtime/vm/type_testing_stubs.h b/runtime/vm/type_testing_stubs.h
index b823215..7807bc1 100644
--- a/runtime/vm/type_testing_stubs.h
+++ b/runtime/vm/type_testing_stubs.h
@@ -24,19 +24,15 @@
//
// (only during dart_boostrap).
const char* StubNameForType(const AbstractType& type) const;
- void WriteStubNameForTypeTo(BaseTextBuffer* buffer,
- const AbstractType& type) const;
private:
- void StringifyTypeTo(BaseTextBuffer* buffer, const AbstractType& type) const;
- // Converts the contents of the buffer to an assembly-safe name.
- static void MakeNameAssemblerSafe(BaseTextBuffer* buffer);
+ const char* StringifyType(const AbstractType& type) const;
+ static const char* AssemblerSafeName(char* cname);
Library& lib_;
Class& klass_;
AbstractType& type_;
String& string_;
- mutable intptr_t nonce_ = 0;
};
class TypeTestingStubGenerator {
diff --git a/tools/VERSION b/tools/VERSION
index 6e500fc..8969d93 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 19
PATCH 0
-PRERELEASE 40
+PRERELEASE 41
PRERELEASE_PATCH 0
\ No newline at end of file