Skip to content

Commit 84a1b11

Browse files
sstricklCommit Queue
authored andcommitted
[vm] Add base class for shared object writers.
This CL pulls out the refactorings used to support the new MachOWriter in a followup CL to allow them to be reviewed separately. Rename Elf -> ElfWriter. Also rename model classes used by ElfWriter for concepts that exist both in ELF and Mach-O to ElfX. For example, the old ELF-specific SymbolTable is renamed to ElfSymbolTable. Adds SharedObjectWriter to serve as a base class for both ElfWriter and the upcoming MachOWriter. Adds a new AbstractWriteStream that serves as a common superclass of both BaseWriteStream and SharedObjectWriter::WriteStream and allows the creation of fully delegating WriteStreams that do not maintain a local buffer. Abstract the old Elf::SymbolData class into SharedObjectWriter::SymbolData, which stores an enum value as the type of the symbol instead of storing the ELF encoding of the type. Rename the DwarfElfStream (which actually wasn't ELF specific, as all the ELF-specific DWARF information is handled by ElfWriter) to DwarfSharedObjectStream and put it in a separate header file. Rename Image::compiled_to_elf() to Image::compiled_to_shared_object() and add a separate Image::compiled_to_elf() that checks for the ELF magic value at the DSO base. Also add Image::shared_object_start() and Image::build_id_start() to return pointers to the DSO base and the build ID note, respectively. Refactor Image::build_id() and Image::build_id_length() to check compiled_for_elf() prior to decoding the data pointed to by build_id_start() as an ELF note section. Create an AOTSnapshotType enum to specific the snapshot writer to use in CreateAppAOTSnapshot instead of using an as_elf boolean. TEST=refactorings, so existing tests on ci Change-Id: Ia3ab37a4dff93b6e00390b123753be5a51fbdaaa Cq-Include-Trybots: luci.dart.try:vm-aot-linux-debug-x64-try,vm-aot-mac-release-arm64-try,vm-aot-dwarf-linux-product-x64-try,vm-linux-debug-x64-try,vm-mac-debug-arm64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/421301 Reviewed-by: Ryan Macnak <[email protected]> Commit-Queue: Tess Strickland <[email protected]>
1 parent ed2f893 commit 84a1b11

File tree

13 files changed

+1026
-709
lines changed

13 files changed

+1026
-709
lines changed

runtime/platform/elf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ namespace elf {
1212

1313
#pragma pack(push, 1)
1414

15+
static constexpr uint8_t ELFMAG[] = {'\x7f', 'E', 'L', 'F'};
16+
1517
struct ElfHeader {
1618
uint8_t ident[16];
1719
uint16_t type;

runtime/vm/dart_api_impl.cc

Lines changed: 51 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6429,11 +6429,16 @@ static constexpr intptr_t kAssemblyInitialSize = 512 * KB;
64296429
static constexpr intptr_t kInitialSize = 2 * MB;
64306430
static constexpr intptr_t kInitialDebugSize = 1 * MB;
64316431

6432+
enum class AOTSnapshotType {
6433+
kAssembly,
6434+
kElf,
6435+
};
6436+
64326437
static void CreateAppAOTSnapshot(
64336438
Dart_StreamingWriteCallback callback,
64346439
void* callback_data,
64356440
bool strip,
6436-
bool as_elf,
6441+
AOTSnapshotType type,
64376442
void* debug_callback_data,
64386443
GrowableArray<LoadingUnitSerializationData*>* units,
64396444
LoadingUnitSerializationData* unit,
@@ -6455,68 +6460,59 @@ static void CreateAppAOTSnapshot(
64556460
(strip && !generate_debug) ? nullptr
64566461
: ImageWriter::CreateReverseObfuscationTrie(T);
64576462

6458-
if (as_elf) {
6459-
StreamingWriteStream elf_stream(kInitialSize, callback, callback_data);
6460-
StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0,
6461-
callback, debug_callback_data);
6462-
6463-
auto const dwarf = strip ? nullptr : new (Z) Dwarf(Z, deobfuscation_trie);
6464-
auto const elf = new (Z) Elf(Z, &elf_stream, Elf::Type::Snapshot, dwarf);
6465-
// Re-use the same DWARF object if the snapshot is unstripped.
6466-
auto const debug_elf =
6467-
generate_debug
6468-
? new (Z) Elf(Z, &debug_stream, Elf::Type::DebugInfo,
6469-
strip ? new (Z) Dwarf(Z, deobfuscation_trie) : dwarf)
6470-
: nullptr;
6471-
6472-
BlobImageWriter image_writer(T, &vm_snapshot_instructions,
6473-
&isolate_snapshot_instructions,
6474-
deobfuscation_trie, debug_elf, elf);
6475-
FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data,
6476-
&isolate_snapshot_data, &image_writer,
6477-
&image_writer);
6463+
StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0,
6464+
callback, debug_callback_data);
6465+
Dwarf* debug_dwarf = nullptr;
6466+
SharedObjectWriter* debug_so = nullptr;
6467+
if (generate_debug) {
6468+
debug_dwarf = new (Z) Dwarf(Z, deobfuscation_trie);
6469+
debug_so = new (Z) ElfWriter(
6470+
Z, &debug_stream, SharedObjectWriter::Type::DebugInfo, debug_dwarf);
6471+
}
64786472

6479-
if (unit == nullptr || unit->id() == LoadingUnit::kRootId) {
6480-
writer.WriteFullSnapshot(units);
6481-
} else {
6482-
writer.WriteUnitSnapshot(units, unit, program_hash);
6483-
}
6473+
StreamingWriteStream output_stream(
6474+
type == AOTSnapshotType::kAssembly ? kAssemblyInitialSize : kInitialSize,
6475+
callback, callback_data);
64846476

6485-
elf->Finalize();
6486-
if (debug_elf != nullptr) {
6487-
debug_elf->Finalize();
6488-
Elf::AssertConsistency(elf, debug_elf);
6489-
}
6490-
} else {
6491-
StreamingWriteStream assembly_stream(kAssemblyInitialSize, callback,
6492-
callback_data);
6493-
StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0,
6494-
callback, debug_callback_data);
6495-
6496-
auto const elf = generate_debug
6497-
? new (Z) Elf(Z, &debug_stream, Elf::Type::DebugInfo,
6498-
new (Z) Dwarf(Z, deobfuscation_trie))
6499-
: nullptr;
6500-
6501-
AssemblyImageWriter image_writer(T, &assembly_stream, deobfuscation_trie,
6502-
strip, elf);
6477+
auto const use_output_writer = [&](ImageWriter* image_writer) {
65036478
FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data,
6504-
&isolate_snapshot_data, &image_writer,
6505-
&image_writer);
6479+
&isolate_snapshot_data, image_writer,
6480+
image_writer);
65066481

65076482
if (unit == nullptr || unit->id() == LoadingUnit::kRootId) {
65086483
writer.WriteFullSnapshot(units);
65096484
} else {
65106485
writer.WriteUnitSnapshot(units, unit, program_hash);
65116486
}
6512-
image_writer.Finalize();
6487+
image_writer->Finalize();
6488+
};
6489+
6490+
Dwarf* const dwarf = (type == AOTSnapshotType::kAssembly || strip) ? nullptr
6491+
: generate_debug ? debug_dwarf
6492+
: new (Z) Dwarf(Z, deobfuscation_trie);
6493+
SharedObjectWriter* so = nullptr;
6494+
if (type == AOTSnapshotType::kElf) {
6495+
so = new (Z)
6496+
ElfWriter(Z, &output_stream, SharedObjectWriter::Type::Snapshot, dwarf);
6497+
}
6498+
6499+
if (type == AOTSnapshotType::kAssembly) {
6500+
ASSERT(so == nullptr);
6501+
AssemblyImageWriter assembly_writer(T, &output_stream, deobfuscation_trie,
6502+
strip, debug_so);
6503+
use_output_writer(&assembly_writer);
6504+
} else {
6505+
BlobImageWriter blob_writer(T, &vm_snapshot_instructions,
6506+
&isolate_snapshot_instructions,
6507+
deobfuscation_trie, debug_so, so);
6508+
use_output_writer(&blob_writer);
65136509
}
65146510
}
65156511

65166512
static void Split(Dart_CreateLoadingUnitCallback next_callback,
65176513
void* next_callback_data,
65186514
bool strip,
6519-
bool as_elf,
6515+
AOTSnapshotType type,
65206516
Dart_StreamingWriteCallback write_callback,
65216517
Dart_StreamingCloseCallback close_callback) {
65226518
Thread* T = Thread::Current();
@@ -6548,7 +6544,7 @@ static void Split(Dart_CreateLoadingUnitCallback next_callback,
65486544
next_callback(next_callback_data, id, &write_callback_data,
65496545
&write_debug_callback_data);
65506546
}
6551-
CreateAppAOTSnapshot(write_callback, write_callback_data, strip, as_elf,
6547+
CreateAppAOTSnapshot(write_callback, write_callback_data, strip, type,
65526548
write_debug_callback_data, &data, data[id],
65536549
program_hash);
65546550
{
@@ -6582,8 +6578,9 @@ Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
65826578
// Mark as not split.
65836579
T->isolate_group()->object_store()->set_loading_units(Object::null_array());
65846580

6585-
CreateAppAOTSnapshot(callback, callback_data, strip, /*as_elf*/ false,
6586-
debug_callback_data, nullptr, nullptr, 0);
6581+
CreateAppAOTSnapshot(callback, callback_data, strip,
6582+
AOTSnapshotType::kAssembly, debug_callback_data, nullptr,
6583+
nullptr, 0);
65876584

65886585
return Api::Success();
65896586
#endif
@@ -6609,7 +6606,7 @@ DART_EXPORT Dart_Handle Dart_CreateAppAOTSnapshotAsAssemblies(
66096606
CHECK_NULL(write_callback);
66106607
CHECK_NULL(close_callback);
66116608

6612-
Split(next_callback, next_callback_data, strip, /*as_elf*/ false,
6609+
Split(next_callback, next_callback_data, strip, AOTSnapshotType::kAssembly,
66136610
write_callback, close_callback);
66146611

66156612
return Api::Success();
@@ -6663,7 +6660,7 @@ Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback,
66636660
// Mark as not split.
66646661
T->isolate_group()->object_store()->set_loading_units(Object::null_array());
66656662

6666-
CreateAppAOTSnapshot(callback, callback_data, strip, /*as_elf*/ true,
6663+
CreateAppAOTSnapshot(callback, callback_data, strip, AOTSnapshotType::kElf,
66676664
debug_callback_data, nullptr, nullptr, 0);
66686665

66696666
return Api::Success();
@@ -6688,7 +6685,7 @@ Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback,
66886685
CHECK_NULL(write_callback);
66896686
CHECK_NULL(close_callback);
66906687

6691-
Split(next_callback, next_callback_data, strip, /*as_elf*/ true,
6688+
Split(next_callback, next_callback_data, strip, AOTSnapshotType::kElf,
66926689
write_callback, close_callback);
66936690

66946691
return Api::Success();

runtime/vm/datastream.h

Lines changed: 96 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -327,18 +327,110 @@ class ReadStream : public ValueObject {
327327
DISALLOW_COPY_AND_ASSIGN(ReadStream);
328328
};
329329

330+
// Base class for streams that write bytes to some backing store. Generally,
331+
// BaseWriteStream is a more appropriate superclass of new WriteStreams since
332+
// it offers more functionality (e.g., Printf).
333+
struct AbstractWriteStream : public ValueObject {
334+
AbstractWriteStream() {}
335+
virtual ~AbstractWriteStream() {}
336+
337+
virtual intptr_t Position() const = 0;
338+
virtual intptr_t Align(intptr_t alignment, intptr_t offset = 0) = 0;
339+
virtual void WriteBytes(const void* addr, intptr_t len) = 0;
340+
virtual void WriteByte(uint8_t value) = 0;
341+
342+
private:
343+
using C = LEB128Constants;
344+
345+
public:
346+
template <typename T>
347+
C::only_if_unsigned<T, void> WriteLEB128(T value) {
348+
T remainder = value;
349+
bool is_last_part;
350+
do {
351+
uint8_t part = static_cast<uint8_t>(remainder & C::kDataByteMask);
352+
remainder >>= C::kDataBitsPerByte;
353+
// For unsigned types, we're done when the remainder has no bits set.
354+
is_last_part = remainder == static_cast<T>(0);
355+
if (!is_last_part) {
356+
// Mark this part as a non-final part for this value.
357+
part |= C::kMoreDataMask;
358+
}
359+
WriteByte(part);
360+
} while (!is_last_part);
361+
}
362+
363+
template <typename T>
364+
C::only_if_signed<T, void> WriteLEB128(T value) {
365+
// If we're trying to LEB128 encode a negative value, chances are we should
366+
// be using SLEB128 instead.
367+
ASSERT(value >= 0);
368+
return WriteLEB128(bit_cast<typename std::make_unsigned<T>::type>(value));
369+
}
370+
371+
template <typename T>
372+
C::only_if_signed<T, void> WriteSLEB128(T value) {
373+
constexpr intptr_t kBitsPerT = kBitsPerByte * sizeof(T);
374+
using Unsigned = typename std::make_unsigned<T>::type;
375+
// Record whether the original value was negative.
376+
const bool is_negative = value < 0;
377+
T remainder = value;
378+
bool is_last_part;
379+
do {
380+
uint8_t part = static_cast<uint8_t>(remainder & C::kDataByteMask);
381+
remainder >>= C::kDataBitsPerByte;
382+
// For signed types, we're done when either:
383+
// - the remainder has all bits set and the part's sign bit is set
384+
// for negative values, or
385+
// - the remainder has no bits set and the part's sign bit is unset for
386+
// non-negative values.
387+
// If the remainder matches but the sign bit does not, we need one more
388+
// part to set the sign bit correctly when decoding.
389+
if (is_negative) {
390+
// Right shifts of negative values in C are not guaranteed to be
391+
// arithmetic. For negative values, set the [kDataBitsPerByte] most
392+
// significant bits after shifting to ensure the value stays negative.
393+
constexpr intptr_t preserved_bits = kBitsPerT - C::kDataBitsPerByte;
394+
// The sign extension mask is the inverse of the preserved bits mask.
395+
constexpr T sign_extend =
396+
~static_cast<T>((static_cast<Unsigned>(1) << preserved_bits) - 1);
397+
// Sign extend for negative values just in case a non-arithmetic right
398+
// shift is used by the compiler.
399+
remainder |= sign_extend;
400+
ASSERT(remainder < 0); // Remainder should still be negative.
401+
is_last_part =
402+
remainder == ~static_cast<T>(0) && (part & C::kSignMask) != 0;
403+
} else {
404+
ASSERT(remainder >= 0); // Remainder should still be non-negative.
405+
is_last_part =
406+
(remainder == static_cast<T>(0) && (part & C::kSignMask) == 0);
407+
}
408+
if (!is_last_part) {
409+
// Mark this part as a non-final part for this value.
410+
part |= C::kMoreDataMask;
411+
}
412+
WriteByte(part);
413+
} while (!is_last_part);
414+
}
415+
416+
template <typename T>
417+
C::only_if_unsigned<T, void> WriteSLEB128(T value) {
418+
return WriteSLEB128(bit_cast<typename std::make_signed<T>::type>(value));
419+
}
420+
};
421+
330422
// Base class for streams that writing various types into a buffer, possibly
331423
// flushing data out periodically to a more permanent store.
332-
class BaseWriteStream : public ValueObject {
424+
class BaseWriteStream : public AbstractWriteStream {
333425
public:
334426
explicit BaseWriteStream(intptr_t initial_size)
335427
: initial_size_(Utils::RoundUpToPowerOfTwo(initial_size)) {}
336-
virtual ~BaseWriteStream() {}
337428

338429
DART_FORCE_INLINE intptr_t bytes_written() const { return Position(); }
339430
virtual intptr_t Position() const { return current_ - buffer_; }
431+
intptr_t initial_size() const { return initial_size_; }
340432

341-
intptr_t Align(intptr_t alignment, intptr_t offset = 0) {
433+
virtual intptr_t Align(intptr_t alignment, intptr_t offset = 0) {
342434
const intptr_t position_before = Position();
343435
const intptr_t position_after =
344436
Utils::RoundUp(position_before, alignment, offset);
@@ -474,92 +566,13 @@ class BaseWriteStream : public ValueObject {
474566
WriteBytes(&value, sizeof(value));
475567
}
476568

477-
DART_FORCE_INLINE void WriteByte(uint8_t value) {
569+
DART_FORCE_INLINE virtual void WriteByte(uint8_t value) {
478570
EnsureSpace(1);
479571
*current_++ = value;
480572
}
481573

482574
void WriteString(const char* cstr) { WriteBytes(cstr, strlen(cstr)); }
483575

484-
private:
485-
using C = LEB128Constants;
486-
487-
public:
488-
template <typename T>
489-
C::only_if_unsigned<T, void> WriteLEB128(T value) {
490-
T remainder = value;
491-
bool is_last_part;
492-
do {
493-
uint8_t part = static_cast<uint8_t>(remainder & C::kDataByteMask);
494-
remainder >>= C::kDataBitsPerByte;
495-
// For unsigned types, we're done when the remainder has no bits set.
496-
is_last_part = remainder == static_cast<T>(0);
497-
if (!is_last_part) {
498-
// Mark this part as a non-final part for this value.
499-
part |= C::kMoreDataMask;
500-
}
501-
WriteByte(part);
502-
} while (!is_last_part);
503-
}
504-
505-
template <typename T>
506-
C::only_if_signed<T, void> WriteLEB128(T value) {
507-
// If we're trying to LEB128 encode a negative value, chances are we should
508-
// be using SLEB128 instead.
509-
ASSERT(value >= 0);
510-
return WriteLEB128(bit_cast<typename std::make_unsigned<T>::type>(value));
511-
}
512-
513-
template <typename T>
514-
C::only_if_signed<T, void> WriteSLEB128(T value) {
515-
constexpr intptr_t kBitsPerT = kBitsPerByte * sizeof(T);
516-
using Unsigned = typename std::make_unsigned<T>::type;
517-
// Record whether the original value was negative.
518-
const bool is_negative = value < 0;
519-
T remainder = value;
520-
bool is_last_part;
521-
do {
522-
uint8_t part = static_cast<uint8_t>(remainder & C::kDataByteMask);
523-
remainder >>= C::kDataBitsPerByte;
524-
// For signed types, we're done when either:
525-
// - the remainder has all bits set and the part's sign bit is set
526-
// for negative values, or
527-
// - the remainder has no bits set and the part's sign bit is unset for
528-
// non-negative values.
529-
// If the remainder matches but the sign bit does not, we need one more
530-
// part to set the sign bit correctly when decoding.
531-
if (is_negative) {
532-
// Right shifts of negative values in C are not guaranteed to be
533-
// arithmetic. For negative values, set the [kDataBitsPerByte] most
534-
// significant bits after shifting to ensure the value stays negative.
535-
constexpr intptr_t preserved_bits = kBitsPerT - C::kDataBitsPerByte;
536-
// The sign extension mask is the inverse of the preserved bits mask.
537-
constexpr T sign_extend =
538-
~static_cast<T>((static_cast<Unsigned>(1) << preserved_bits) - 1);
539-
// Sign extend for negative values just in case a non-arithmetic right
540-
// shift is used by the compiler.
541-
remainder |= sign_extend;
542-
ASSERT(remainder < 0); // Remainder should still be negative.
543-
is_last_part =
544-
remainder == ~static_cast<T>(0) && (part & C::kSignMask) != 0;
545-
} else {
546-
ASSERT(remainder >= 0); // Remainder should still be non-negative.
547-
is_last_part =
548-
(remainder == static_cast<T>(0) && (part & C::kSignMask) == 0);
549-
}
550-
if (!is_last_part) {
551-
// Mark this part as a non-final part for this value.
552-
part |= C::kMoreDataMask;
553-
}
554-
WriteByte(part);
555-
} while (!is_last_part);
556-
}
557-
558-
template <typename T>
559-
C::only_if_unsigned<T, void> WriteSLEB128(T value) {
560-
return WriteSLEB128(bit_cast<typename std::make_signed<T>::type>(value));
561-
}
562-
563576
protected:
564577
void EnsureSpace(intptr_t size_needed) {
565578
if (Remaining() >= size_needed) return;

0 commit comments

Comments
 (0)