20#if defined(DART_PRECOMPILER)
24class ElfWriteStream :
public ValueObject {
26 explicit ElfWriteStream(BaseWriteStream*
stream,
const Elf& elf)
29 start_(stream_->Position()) {
37 const Elf& elf()
const {
return elf_; }
41 intptr_t Position()
const {
return stream_->Position() - start_; }
42 void Align(
const intptr_t alignment) {
45 stream_->Align(alignment);
47 void WriteBytes(
const uint8_t*
b, intptr_t
size) {
48 stream_->WriteBytes(
b,
size);
50 void WriteByte(uint8_t
value) { stream_->WriteByte(
value); }
51 void WriteHalf(uint16_t
value) { stream_->WriteFixed(
value); }
52 void WriteWord(uint32_t
value) { stream_->WriteFixed(
value); }
55#if defined(TARGET_ARCH_IS_64_BIT)
56 void WriteXWord(uint64_t
value) { stream_->WriteFixed(
value); }
60 BaseWriteStream*
const stream_;
62 const intptr_t start_;
65static constexpr intptr_t kLinearInitValue = -1;
67#define DEFINE_LINEAR_FIELD_METHODS(name) \
68 intptr_t name() const { \
69 ASSERT(name##_ != kLinearInitValue); \
72 bool name##_is_set() const { \
73 return name##_ != kLinearInitValue; \
75 void set_##name(intptr_t value) { \
76 ASSERT(value != kLinearInitValue); \
77 ASSERT_EQUAL(name##_, kLinearInitValue); \
81#define DEFINE_LINEAR_FIELD(name) intptr_t name##_ = kLinearInitValue;
85#define FOR_EACH_SECTION_TYPE(V) \
90 V(TextSection) V(DataSection) V(BssSection) V(PseudoSection) V(SectionTable)
91#define DEFINE_TYPE_CHECK_FOR(Type) \
92 bool Is##Type() const { \
96#define DECLARE_SECTION_TYPE_CLASS(Type) class Type;
97FOR_EACH_SECTION_TYPE(DECLARE_SECTION_TYPE_CLASS)
98#undef DECLARE_SECTION_TYPE_CLASS
104static constexpr intptr_t kNoteAlignment = 4;
106class Section :
public ZoneAllocated {
114 flags(EncodeFlags(allocate, executable, writable)),
117 memory_offset_(allocate ? kLinearInitValue : 0) {
126 virtual ~Section() {}
131 const intptr_t
flags;
132 const intptr_t alignment;
138 intptr_t entry_size = 0;
143#define FOR_EACH_SECTION_LINEAR_FIELD(M) \
147 FOR_EACH_SECTION_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
151 virtual intptr_t FileSize()
const {
152 if (!IsAllocated()) {
160#define FOR_EACH_SEGMENT_LINEAR_FIELD(M) M(memory_offset)
162 FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
165 virtual intptr_t MemorySize()
const {
174 bool IsAllocated()
const {
185 bool HasBeenFinalized()
const {
188 return file_offset_is_set();
191#define DEFINE_BASE_TYPE_CHECKS(Type) \
193 return Is##Type() ? reinterpret_cast<Type*>(this) : nullptr; \
195 const Type* As##Type() const { \
196 return const_cast<Type*>(const_cast<Section*>(this)->As##Type()); \
198 virtual bool Is##Type() const { return false; }
200 FOR_EACH_SECTION_TYPE(DEFINE_BASE_TYPE_CHECKS)
201#undef DEFINE_BASE_TYPE_CHECKS
204 virtual bool CanMergeWith(
const Section& other)
const {
return false; }
210 virtual void WriteSectionHeader(ElfWriteStream*
stream)
const {
211#if defined(TARGET_ARCH_IS_32_BIT)
213 stream->WriteWord(
static_cast<uint32_t
>(
type));
215 stream->WriteAddr(memory_offset());
216 stream->WriteOff(file_offset());
217 stream->WriteWord(FileSize());
220 stream->WriteWord(alignment);
221 stream->WriteWord(entry_size);
224 stream->WriteWord(
static_cast<uint32_t
>(
type));
226 stream->WriteAddr(memory_offset());
227 stream->WriteOff(file_offset());
228 stream->WriteXWord(FileSize());
231 stream->WriteXWord(alignment);
232 stream->WriteXWord(entry_size);
237 static intptr_t EncodeFlags(
bool allocate,
bool executable,
bool writable) {
239 ASSERT(!executable || !writable);
247 FOR_EACH_SECTION_LINEAR_FIELD(DEFINE_LINEAR_FIELD);
248 FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD);
250#undef FOR_EACH_SECTION_LINEAR_FIELD
251#undef FOR_EACH_SEGMENT_LINEAR_FIELD
254#undef DEFINE_LINEAR_FIELD
255#undef DEFINE_LINEAR_FIELD_METHODS
257class Segment :
public ZoneAllocated {
262 :
type(segment_type),
271 ASSERT(initial_section !=
nullptr);
272 sections_.Add(initial_section);
275 virtual ~Segment() {}
277 const GrowableArray<Section*>& sections()
const {
return sections_; }
279 intptr_t Alignment()
const {
287 return kNoteAlignment;
299 void WriteProgramHeader(ElfWriteStream*
stream)
const {
300#if defined(TARGET_ARCH_IS_32_BIT)
301 stream->WriteWord(
static_cast<uint32_t
>(
type));
302 stream->WriteOff(FileOffset());
303 stream->WriteAddr(MemoryOffset());
304 stream->WriteAddr(MemoryOffset());
305 stream->WriteWord(FileSize());
306 stream->WriteWord(MemorySize());
308 stream->WriteWord(Alignment());
310 stream->WriteWord(
static_cast<uint32_t
>(
type));
312 stream->WriteOff(FileOffset());
313 stream->WriteAddr(MemoryOffset());
314 stream->WriteAddr(MemoryOffset());
315 stream->WriteXWord(FileSize());
316 stream->WriteXWord(MemorySize());
317 stream->WriteXWord(Alignment());
324 ASSERT(section !=
nullptr);
326 ASSERT(!section->memory_offset_is_set());
334 sections_.Add(section);
338 intptr_t FileOffset()
const {
return sections_[0]->file_offset(); }
340 intptr_t FileSize()
const {
341 auto const last = sections_.Last();
342 const intptr_t
end = last->file_offset() + last->FileSize();
343 return end - FileOffset();
346 intptr_t MemoryOffset()
const {
return sections_[0]->memory_offset(); }
348 intptr_t MemorySize()
const {
349 auto const last = sections_.Last();
350 const intptr_t
end = last->memory_offset() + last->MemorySize();
351 return end - MemoryOffset();
354 intptr_t MemoryEnd()
const {
return MemoryOffset() + MemorySize(); }
357 const intptr_t
flags;
360 static intptr_t EncodeFlags(
bool executable,
bool writable) {
367 GrowableArray<Section*> sections_;
372class ReservedSection :
public Section {
383 DEFINE_TYPE_CHECK_FOR(ReservedSection);
384 intptr_t FileSize()
const {
return 0; }
389class GnuStackSection :
public Section {
399 intptr_t FileSize()
const {
return 0; }
402class StringTable :
public Section {
404 explicit StringTable(Zone* zone,
bool allocate)
411 text_indices_(zone) {
415 intptr_t FileSize()
const {
return text_.length(); }
416 intptr_t MemorySize()
const {
return dynamic_ ? FileSize() : 0; }
418 void Write(ElfWriteStream*
stream)
const {
419 stream->WriteBytes(
reinterpret_cast<const uint8_t*
>(text_.buffer()),
423 intptr_t Add(
const char* str) {
425 if (
auto const kv = text_indices_.Lookup(str)) {
428 intptr_t
offset = text_.length();
429 text_.AddString(str);
431 text_indices_.Insert({str,
offset});
435 const char* At(intptr_t index)
const {
436 if (index >= text_.length())
return nullptr;
437 return text_.buffer() + index;
444 intptr_t Lookup(
const char* str)
const {
445 return text_indices_.LookupValue(str);
449 ZoneTextBuffer text_;
450 CStringIntMap text_indices_;
453class SymbolTable :
public Section {
455 SymbolTable(Zone* zone, StringTable*
table,
bool dynamic)
465 by_label_index_(zone) {
466 link = table_->index;
467 entry_size =
sizeof(elf::Symbol);
479 DEFINE_TYPE_CHECK_FOR(SymbolTable)
480 const StringTable& strtab()
const {
return *table_; }
481 intptr_t FileSize()
const {
return symbols_.length() * entry_size; }
482 intptr_t MemorySize()
const {
return dynamic_ ? FileSize() : 0; }
485 void Write(ElfWriteStream*
stream)
const {
488 stream->WriteWord(name_index);
489#if defined(TARGET_ARCH_IS_32_BIT)
494 stream->WriteHalf(section_index);
498 stream->WriteHalf(section_index);
510 intptr_t section_index;
522 const GrowableArray<Symbol>&
symbols()
const {
return symbols_; }
524 void Initialize(
const GrowableArray<Section*>& sections);
526 void Write(ElfWriteStream*
stream)
const {
527 for (
const auto& symbol : symbols_) {
534 void AddSymbol(
const char*
name,
542 ASSERT(!table_->HasBeenFinalized());
543 auto const name_index = table_->Add(
name);
545 const intptr_t new_index = symbols_.length();
546 symbols_.Add({name_index, binding,
type,
size, index,
offset, label});
547 by_label_index_.Insert(label, new_index);
552 if (
info != new_index) {
558 symbols_.Swap(
info, new_index);
560 by_label_index_.Update({symbols_[
info].label,
info});
561 by_label_index_.Update({symbols_[new_index].label, new_index});
567 void UpdateSectionIndices(
const GrowableArray<intptr_t>& index_map) {
569 const intptr_t map_size = index_map.length();
573 for (intptr_t
i = 1;
i < map_size;
i++) {
575 ASSERT(index_map[
i] < map_size);
578 for (
auto& symbol : symbols_) {
580 symbol.section_index = index_map[symbol.section_index];
584 void Finalize(
const GrowableArray<intptr_t>& address_map) {
586 const intptr_t map_size = address_map.length();
590 for (intptr_t
i = 1;
i < map_size;
i++) {
595 for (
auto& symbol : symbols_) {
597 symbol.offset += address_map[symbol.section_index];
601 const Symbol* FindUid(intptr_t label)
const {
603 const intptr_t symbols_index = by_label_index_.Lookup(label);
604 if (symbols_index == 0)
return nullptr;
605 return &symbols_[symbols_index];
610 StringTable*
const table_;
612 GrowableArray<Symbol> symbols_;
615 IntMap<intptr_t> by_label_index_;
618class SymbolHashTable :
public Section {
620 SymbolHashTable(Zone* zone, SymbolTable* symtab)
627 link = symtab->index;
628 entry_size =
sizeof(int32_t);
630 const auto&
symbols = symtab->symbols();
631 const intptr_t num_symbols =
symbols.length();
635 for (intptr_t
i = 1;
i < num_symbols;
i++) {
637 uint32_t
hash = HashSymbolName(symtab->strtab().At(symbol.name_index));
638 uint32_t probe =
hash % num_symbols;
639 chains_[
i] = buckets_[probe];
644 intptr_t MemorySize()
const {
645 return entry_size * (buckets_.length() + chains_.length() + 2);
648 void Write(ElfWriteStream*
stream)
const {
649 stream->WriteWord(buckets_.length());
650 stream->WriteWord(chains_.length());
651 for (
const int32_t bucket : buckets_) {
652 stream->WriteWord(bucket);
654 for (
const int32_t chain : chains_) {
659 static uint32_t HashSymbolName(
const void*
p) {
660 auto*
name =
reinterpret_cast<const uint8_t*
>(
p);
662 while (*
name !=
'\0') {
664 uint32_t g =
h & 0xf0000000;
672 GrowableArray<int32_t> buckets_;
673 GrowableArray<int32_t> chains_;
676class DynamicTable :
public Section {
681 DynamicTable(Zone* zone, SymbolTable* symtab, SymbolHashTable*
hash)
688 link = strtab().index;
689 entry_size =
sizeof(elf::DynamicEntry);
699 static constexpr intptr_t kInvalidEntry = -1;
701 DEFINE_TYPE_CHECK_FOR(DynamicTable)
702 const SymbolHashTable&
hash()
const {
return *hash_; }
703 const SymbolTable& symtab()
const {
return *symtab_; }
704 const StringTable& strtab()
const {
return symtab().strtab(); }
705 intptr_t MemorySize()
const {
return entries_.length() * entry_size; }
707 void Write(ElfWriteStream*
stream)
const {
708 for (intptr_t
i = 0;
i < entries_.length();
i++) {
721 struct Entry :
public ZoneAllocated {
724 void Write(ElfWriteStream*
stream)
const {
727#if defined(TARGET_ARCH_IS_32_BIT)
728 stream->WriteWord(
static_cast<uint32_t
>(tag));
731 stream->WriteXWord(
static_cast<uint64_t
>(tag));
742 auto const entry =
new (zone)
Entry(tag,
value);
747 for (
auto* entry : entries_) {
748 if (entry->tag == tag) {
749 entry->value =
value;
755 SymbolTable*
const symtab_;
756 SymbolHashTable*
const hash_;
757 GrowableArray<Entry*> entries_;
760class BitsContainer :
public Section {
769 :
Section(
type, allocate, executable, writable, alignment) {}
773 : BitsContainer(
type,
785 intptr_t alignment = 1)
786 : BitsContainer(t == Elf::
Type::Snapshot
794 DEFINE_TYPE_CHECK_FOR(BitsContainer)
797 bool HasBytes()
const {
798 return portions_.length() != 0 && portions_[0].bytes !=
nullptr;
802 void Write(ElfWriteStream*
stream, intptr_t section_start)
const {
804 if (relocations ==
nullptr) {
808 const SymbolTable& symtab =
stream->elf().symtab();
810 intptr_t current_pos = 0;
811 for (
const auto& reloc : *relocations) {
814 ASSERT(current_pos <= reloc.section_offset);
815 if (current_pos < reloc.section_offset) {
816 stream->WriteBytes(bytes + current_pos,
817 reloc.section_offset - current_pos);
819 intptr_t source_address = reloc.source_offset;
820 if (reloc.source_label > 0) {
821 auto*
const source_symbol = symtab.FindUid(reloc.source_label);
822 ASSERT(source_symbol !=
nullptr);
823 source_address += source_symbol->offset;
824 }
else if (reloc.source_label == Elf::Relocation::kSelfRelative) {
825 source_address += section_start +
offset + reloc.section_offset;
827 ASSERT_EQUAL(reloc.source_label, Elf::Relocation::kSnapshotRelative);
831 word to_write = reloc.target_offset - source_address;
832 if (reloc.target_label > 0) {
833 if (
auto*
const target_symbol = symtab.FindUid(reloc.target_label)) {
834 to_write += target_symbol->offset;
843 to_write = Image::kNoRelocatedAddress;
845 }
else if (reloc.target_label == Elf::Relocation::kSelfRelative) {
846 to_write += section_start +
offset + reloc.section_offset;
848 ASSERT_EQUAL(reloc.target_label, Elf::Relocation::kSnapshotRelative);
852 stream->WriteBytes(
reinterpret_cast<const uint8_t*
>(&to_write),
853 reloc.size_in_bytes);
854 current_pos = reloc.section_offset + reloc.size_in_bytes;
856 stream->WriteBytes(bytes + current_pos,
size - current_pos);
860 const char* symbol_name;
862 const uint8_t* bytes;
864 const ZoneGrowableArray<Elf::Relocation>* relocations;
865 const ZoneGrowableArray<Elf::SymbolData>*
symbols;
871 const GrowableArray<Portion>& portions()
const {
return portions_; }
873 const Portion& AddPortion(
874 const uint8_t* bytes,
876 const ZoneGrowableArray<Elf::Relocation>* relocations =
nullptr,
877 const ZoneGrowableArray<Elf::SymbolData>*
symbols =
nullptr,
878 const char* symbol_name =
nullptr,
879 intptr_t label = 0) {
881 ASSERT(symbol_name ==
nullptr || label > 0);
882 ASSERT(IsNoBits() || bytes !=
nullptr);
883 ASSERT(bytes !=
nullptr || relocations ==
nullptr);
885 ASSERT(portions_.is_empty() || HasBytes() == (bytes !=
nullptr));
889 const Portion& portion = portions_.Last();
894 void Write(ElfWriteStream*
stream)
const {
896 intptr_t start_position =
stream->Position();
897 for (
const auto& portion : portions_) {
900 portion.Write(
stream, memory_offset());
907 uint32_t
Hash(
const char* symbol_name)
const {
908 for (
const auto& portion : portions_) {
909 if (strcmp(symbol_name, portion.symbol_name) == 0) {
910 if (portion.bytes ==
nullptr)
return 0;
919 intptr_t FileSize()
const {
return IsNoBits() ? 0 : total_size_; }
920 intptr_t MemorySize()
const {
return IsAllocated() ? total_size_ : 0; }
923 GrowableArray<Portion> portions_;
924 intptr_t total_size_ = 0;
927class NoteSection :
public BitsContainer {
939class ConcatenableBitsContainer :
public BitsContainer {
945 : BitsContainer(
type, executable, writable, alignment) {}
947 virtual bool CanMergeWith(
const Section& other)
const = 0;
948 virtual void Merge(
const Section& other) {
949 ASSERT(other.IsBitsContainer());
950 ASSERT(CanMergeWith(other));
951 for (
const auto& portion : other.AsBitsContainer()->portions()) {
952 AddPortion(portion.bytes, portion.size, portion.relocations,
953 portion.symbols, portion.symbol_name, portion.label);
958class TextSection :
public ConcatenableBitsContainer {
961 : ConcatenableBitsContainer(t,
964 ImageWriter::kTextAlignment) {}
966 DEFINE_TYPE_CHECK_FOR(TextSection);
968 virtual bool CanMergeWith(
const Section& other)
const {
969 return other.IsTextSection();
973class DataSection :
public ConcatenableBitsContainer {
976 : ConcatenableBitsContainer(t,
979 ImageWriter::kRODataAlignment) {}
981 DEFINE_TYPE_CHECK_FOR(DataSection);
983 virtual bool CanMergeWith(
const Section& other)
const {
984 return other.IsDataSection();
988class BssSection :
public ConcatenableBitsContainer {
991 : ConcatenableBitsContainer(t,
994 ImageWriter::kBssAlignment) {}
996 DEFINE_TYPE_CHECK_FOR(BssSection);
998 virtual bool CanMergeWith(
const Section& other)
const {
999 return other.IsBssSection();
1006class PseudoSection :
public Section {
1011 PseudoSection(
bool allocate,
bool executable,
bool writable)
1018 DEFINE_TYPE_CHECK_FOR(PseudoSection)
1020 void Write(ElfWriteStream*
stream)
const = 0;
1023class ProgramTable :
public PseudoSection {
1025 explicit ProgramTable(Zone* zone)
1026 : PseudoSection(
true,
1029 segments_(zone, 0) {
1030 entry_size =
sizeof(elf::ProgramHeader);
1033 const GrowableArray<Segment*>& segments()
const {
return segments_; }
1034 intptr_t SegmentCount()
const {
return segments_.length(); }
1035 intptr_t MemorySize()
const {
1036 return segments_.length() *
sizeof(elf::ProgramHeader);
1039 void Add(Segment* segment) {
1040 ASSERT(segment !=
nullptr);
1041 segments_.Add(segment);
1044 void Write(ElfWriteStream*
stream)
const;
1047 GrowableArray<Segment*> segments_;
1052class SectionTable :
public PseudoSection {
1054 explicit SectionTable(Zone* zone)
1055 : PseudoSection(
false,
1059 sections_(zone_, 2),
1060 shstrtab_(zone_,
false) {
1061 entry_size =
sizeof(elf::SectionHeader);
1064 Add(
new (zone_) ReservedSection(),
"");
1065 Add(&shstrtab_,
".shstrtab");
1068 const GrowableArray<Section*>& sections()
const {
return sections_; }
1069 intptr_t SectionCount()
const {
return sections_.length(); }
1070 intptr_t StringTableIndex()
const {
return shstrtab_.index; }
1072 bool HasSectionNamed(
const char*
name) {
1073 return shstrtab_.Lookup(
name) != StringTable::kNotIndexed;
1076 void Add(
Section* section,
const char*
name =
nullptr) {
1077 ASSERT(!section->IsPseudoSection());
1078 ASSERT(
name !=
nullptr || section->name_is_set());
1079 if (
name !=
nullptr) {
1081 if (
auto*
const old_section = Find(
name)) {
1082 ASSERT(old_section->CanMergeWith(*section));
1083 old_section->Merge(*section);
1087 const intptr_t name_index = shstrtab_.Add(
name);
1088 section->set_name(name_index);
1090 section->index = sections_.length();
1091 sections_.Add(section);
1095 const intptr_t name_index = shstrtab_.Lookup(
name);
1096 if (name_index == StringTable::kNotIndexed) {
1102 for (
Section*
const section : sections_) {
1103 if (section->name() == name_index) {
1115 intptr_t FileSize()
const {
1116 return sections_.length() *
sizeof(elf::SectionHeader);
1119 void Write(ElfWriteStream*
stream)
const;
1126 ProgramTable* CreateProgramTable(SymbolTable* symtab);
1130 GrowableArray<Section*> sections_;
1131 StringTable shstrtab_;
1134class ElfHeader :
public PseudoSection {
1136 ElfHeader(
const ProgramTable& program_table,
1137 const SectionTable& section_table)
1138 : PseudoSection(
true,
1141 program_table_(program_table),
1142 section_table_(section_table) {}
1144 intptr_t MemorySize()
const {
return sizeof(elf::ElfHeader); }
1146 void Write(ElfWriteStream*
stream)
const;
1149 const ProgramTable& program_table_;
1150 const SectionTable& section_table_;
1153#undef DEFINE_TYPE_CHECK_FOR
1154#undef FOR_EACH_SECTION_TYPE
1156Elf::Elf(Zone* zone, BaseWriteStream*
stream,
Type type, Dwarf* dwarf)
1158 unwrapped_stream_(
stream),
1161 section_table_(new(zone) SectionTable(zone)) {
1163 ASSERT(type_ == Type::Snapshot || dwarf_ !=
nullptr);
1168void Elf::AddText(
const char*
name,
1170 const uint8_t* bytes,
1172 const ZoneGrowableArray<Relocation>* relocations,
1173 const ZoneGrowableArray<SymbolData>*
symbols) {
1174 auto*
const container =
new (zone_) TextSection(type_);
1175 container->AddPortion(bytes,
size, relocations,
symbols,
name, label);
1176 section_table_->Add(container, kTextName);
1179void Elf::CreateBSS() {
1181 ASSERT(section_table_->Find(kBssName) ==
nullptr);
1183 auto*
const text_section = section_table_->Find(kTextName);
1184 if (text_section ==
nullptr)
return;
1185 ASSERT(text_section->IsTextSection());
1187 auto*
const bss_container =
new (zone_) BssSection(type_);
1188 for (
const auto& portion : text_section->AsBitsContainer()->portions()) {
1190 const char* symbol_name;
1196 label = kVmBssLabel;
1197 }
else if (strcmp(portion.symbol_name,
1201 label = kIsolateBssLabel;
1208 uint8_t* bytes =
nullptr;
1209 if (type_ == Type::Snapshot) {
1215 bytes = zone_->Alloc<uint8_t>(
size);
1216 memset(bytes, 0,
size);
1221 auto*
symbols =
new (zone_) ZoneGrowableArray<Elf::SymbolData>();
1223 bss_container->AddPortion(bytes,
size,
nullptr,
symbols);
1226 section_table_->Add(bss_container, kBssName);
1229void Elf::AddROData(
const char*
name,
1231 const uint8_t* bytes,
1233 const ZoneGrowableArray<Relocation>* relocations,
1234 const ZoneGrowableArray<SymbolData>*
symbols) {
1235 auto*
const container =
new (zone_) DataSection(type_);
1236 container->AddPortion(bytes,
size, relocations,
symbols,
name, label);
1237 section_table_->Add(container, kDataName);
1240#if defined(DART_PRECOMPILER)
1241class DwarfElfStream :
public DwarfWriteStream {
1243 DwarfElfStream(Zone* zone, NonStreamingWriteStream*
stream)
1246 relocations_(new(zone) ZoneGrowableArray<Elf::Relocation>()) {}
1248 const uint8_t*
buffer()
const {
return stream_->buffer(); }
1249 intptr_t bytes_written()
const {
return stream_->bytes_written(); }
1250 intptr_t Position()
const {
return stream_->Position(); }
1252 void sleb128(intptr_t
value) { stream_->WriteSLEB128(
value); }
1253 void uleb128(uintptr_t
value) { stream_->WriteLEB128(
value); }
1254 void u1(uint8_t
value) { stream_->WriteByte(
value); }
1255 void u2(uint16_t
value) { stream_->WriteFixed(
value); }
1256 void u4(uint32_t
value) { stream_->WriteFixed(
value); }
1257 void u8(uint64_t
value) { stream_->WriteFixed(
value); }
1258 void string(
const char* cstr) {
1260 stream_->WriteBytes(cstr, strlen(cstr) + 1);
1264 const intptr_t fixup = stream_->Position();
1269 const intptr_t
start = stream_->Position();
1271 const intptr_t
end = stream_->Position();
1272 stream_->SetPosition(fixup);
1274 stream_->SetPosition(
end);
1278 WritePrefixedLength(
nullptr, body);
1281 void OffsetFromSymbol(intptr_t label, intptr_t
offset) {
1282 relocations_->Add({kAddressSize, stream_->Position(),
1283 Elf::Relocation::kSnapshotRelative, 0, label,
offset});
1286 template <
typename T>
1287 void RelativeSymbolOffset(intptr_t label) {
1288 relocations_->Add({
sizeof(
T), stream_->Position(),
1289 Elf::Relocation::kSelfRelative, 0, label, 0});
1290 stream_->WriteFixed<
T>(0);
1292 void InitializeAbstractOrigins(intptr_t
size) {
1293 abstract_origins_size_ =
size;
1294 abstract_origins_ = zone_->Alloc<uint32_t>(abstract_origins_size_);
1296 void RegisterAbstractOrigin(intptr_t index) {
1297 ASSERT(abstract_origins_ !=
nullptr);
1298 ASSERT(index < abstract_origins_size_);
1299 abstract_origins_[index] = stream_->Position();
1301 void AbstractOrigin(intptr_t index) { u4(abstract_origins_[index]); }
1303 const ZoneGrowableArray<Elf::Relocation>* relocations()
const {
1304 return relocations_;
1308#if defined(TARGET_ARCH_IS_32_BIT)
1309 static constexpr intptr_t kAddressSize =
kInt32Size;
1311 static constexpr intptr_t kAddressSize =
kInt64Size;
1315#if defined(TARGET_ARCH_IS_32_BIT)
1323 NonStreamingWriteStream*
const stream_;
1324 ZoneGrowableArray<Elf::Relocation>* relocations_ =
nullptr;
1325 uint32_t* abstract_origins_ =
nullptr;
1326 intptr_t abstract_origins_size_ = -1;
1332static constexpr intptr_t kInitialDwarfBufferSize = 64 *
KB;
1336 for (
auto*
const section : sections) {
1338 if (!section->IsAllocated())
continue;
1339 if (
auto*
const bits = section->AsBitsContainer()) {
1340 for (
const auto& portion : section->AsBitsContainer()->portions()) {
1341 if (portion.symbol_name !=
nullptr) {
1349 AddSymbol(portion.symbol_name, binding,
type, portion.size,
1350 section->index, portion.offset, portion.label);
1352 if (!dynamic_ && portion.symbols !=
nullptr) {
1353 for (
const auto& symbol_data : *portion.symbols) {
1356 symbol_data.size, section->index,
1357 portion.offset + symbol_data.offset, symbol_data.label);
1365void Elf::InitializeSymbolTables() {
1367 ASSERT(symtab_ ==
nullptr);
1370 auto*
const dynstrtab =
new (zone_) StringTable(zone_,
true);
1371 section_table_->Add(dynstrtab,
".dynstr");
1372 auto*
const dynsym =
1373 new (zone_) SymbolTable(zone_, dynstrtab,
true);
1374 section_table_->Add(dynsym,
".dynsym");
1375 dynsym->Initialize(section_table_->sections());
1378 auto*
const hash =
new (zone_) SymbolHashTable(zone_, dynsym);
1379 section_table_->Add(
hash,
".hash");
1380 auto*
const dynamic =
new (zone_) DynamicTable(zone_, dynsym,
hash);
1381 section_table_->Add(dynamic, kDynamicTableName);
1386 auto*
const strtab =
new (zone_) StringTable(zone_,
false);
1387 if (!IsStripped()) {
1388 section_table_->Add(strtab,
".strtab");
1390 symtab_ =
new (zone_) SymbolTable(zone_, strtab,
false);
1391 if (!IsStripped()) {
1392 section_table_->Add(symtab_,
".symtab");
1394 symtab_->Initialize(section_table_->sections());
1397void Elf::FinalizeEhFrame() {
1398#if !defined(TARGET_ARCH_IA32)
1399#if defined(TARGET_ARCH_X64)
1402 const intptr_t DWARF_RA = 16;
1403 const intptr_t DWARF_FP = 6;
1406 const intptr_t DWARF_FP =
FP;
1410 TextSection* text_section =
nullptr;
1411 if (
auto*
const section = section_table_->Find(kTextName)) {
1412 text_section = section->AsTextSection();
1413 ASSERT(text_section !=
nullptr);
1416 if (text_section ==
nullptr)
return;
1418#if defined(DART_TARGET_OS_WINDOWS) && \
1419 (defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64))
1422 auto*
const unwinding_instructions_frame =
new (zone_) TextSection(type_);
1426 uint8_t* unwinding_instructions =
1429 intptr_t start_offset =
1430 Utils::RoundUp(text_section->FileSize(), text_section->alignment);
1431 stream.WriteBytes(UnwindingRecords::GenerateRecordsInto(
1432 start_offset, unwinding_instructions),
1435 unwinding_instructions_frame->AddPortion(
stream.buffer(),
1437 section_table_->Add(unwinding_instructions_frame, kTextName);
1445 static constexpr uint8_t DW_EH_PE_pcrel = 0x10;
1446 static constexpr uint8_t DW_EH_PE_sdata4 = 0x0b;
1448 ZoneWriteStream
stream(zone(), kInitialDwarfBufferSize);
1449 DwarfElfStream dwarf_stream(zone_, &
stream);
1454 const intptr_t cie_start = dwarf_stream.Position();
1455 dwarf_stream.WritePrefixedLength([&] {
1459 dwarf_stream.string(
"zR");
1460 dwarf_stream.uleb128(1);
1461 dwarf_stream.sleb128(kDataAlignment);
1462 dwarf_stream.u1(DWARF_RA);
1463 dwarf_stream.uleb128(1);
1464 dwarf_stream.u1(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
1466 dwarf_stream.u1(Dwarf::DW_CFA_def_cfa);
1467 dwarf_stream.uleb128(DWARF_FP);
1472 const auto cfa_offset = [&](intptr_t reg, intptr_t
offset) {
1473 const intptr_t scaled_offset =
offset / kDataAlignment;
1475 dwarf_stream.u1(Dwarf::DW_CFA_offset | reg);
1476 dwarf_stream.uleb128(scaled_offset);
1480 for (
const auto& portion : text_section->portions()) {
1481#if defined(DART_TARGET_OS_WINDOWS) && \
1482 (defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64))
1483 if (portion.label == 0) {
1488 ASSERT(portion.label != 0);
1489 dwarf_stream.WritePrefixedLength([&]() {
1492 dwarf_stream.u4(
stream.Position() - cie_start);
1494 dwarf_stream.RelativeSymbolOffset<int32_t>(portion.label);
1495 dwarf_stream.u4(portion.size);
1514 auto*
const eh_frame =
new (zone_)
1515 BitsContainer(type_,
false,
false);
1516 eh_frame->AddPortion(dwarf_stream.buffer(), dwarf_stream.bytes_written(),
1517 dwarf_stream.relocations());
1518 section_table_->Add(eh_frame,
".eh_frame");
1522void Elf::FinalizeDwarfSections() {
1523 if (dwarf_ ==
nullptr)
return;
1526 ASSERT(section_table_->HasSectionNamed(kTextName));
1528 auto add_debug = [&](
const char*
name,
const DwarfElfStream&
stream) {
1529 auto const container =
1530 new (zone_) BitsContainer(elf::SectionHeaderType::SHT_PROGBITS);
1531 container->AddPortion(
stream.buffer(),
stream.bytes_written(),
1533 section_table_->Add(container,
name);
1536 ZoneWriteStream
stream(zone(), kInitialDwarfBufferSize);
1537 DwarfElfStream dwarf_stream(zone_, &
stream);
1538 dwarf_->WriteAbbreviations(&dwarf_stream);
1539 add_debug(
".debug_abbrev", dwarf_stream);
1543 ZoneWriteStream
stream(zone(), kInitialDwarfBufferSize);
1544 DwarfElfStream dwarf_stream(zone_, &
stream);
1545 dwarf_->WriteDebugInfo(&dwarf_stream);
1546 add_debug(
".debug_info", dwarf_stream);
1550 ZoneWriteStream
stream(zone(), kInitialDwarfBufferSize);
1551 DwarfElfStream dwarf_stream(zone_, &
stream);
1552 dwarf_->WriteLineNumberProgram(&dwarf_stream);
1553 add_debug(
".debug_line", dwarf_stream);
1557ProgramTable* SectionTable::CreateProgramTable(SymbolTable* symtab) {
1558 const intptr_t num_sections = sections_.length();
1560 ASSERT(!sections_.is_empty());
1565 auto*
const program_table =
new (zone_) ProgramTable(zone_);
1567 GrowableArray<Section*> reordered_sections(zone_, num_sections);
1569 GrowableArray<intptr_t> index_map(zone_, num_sections);
1570 index_map.FillWith(0, 0, num_sections);
1572 Segment* current_segment =
nullptr;
1575 auto add_to_reordered_sections = [&](
Section* section) {
1576 intptr_t new_index = reordered_sections.length();
1577 index_map[section->index] = new_index;
1578 section->index = new_index;
1579 reordered_sections.Add(section);
1580 if (section->IsAllocated()) {
1581 ASSERT(current_segment !=
nullptr);
1582 if (!current_segment->Add(section)) {
1585 current_segment =
new (zone_)
1586 Segment(zone_, section, elf::ProgramHeaderType::PT_LOAD);
1587 program_table->Add(current_segment);
1594 add_to_reordered_sections(sections_[0]);
1619 auto*
const elf_header =
new (zone_) ElfHeader(*program_table, *
this);
1623 program_table->Add(
new (zone_) Segment(zone_, program_table,
1624 elf::ProgramHeaderType::PT_PHDR));
1629 new (zone_) Segment(zone_, elf_header, elf::ProgramHeaderType::PT_LOAD);
1630 program_table->Add(current_segment);
1631 current_segment->Add(program_table);
1636 auto add_sections_matching =
1641 for (
auto*
const section : sections_) {
1642 if (!section->HasBits())
continue;
1643 if (should_add(section)) {
1644 add_to_reordered_sections(section);
1647 for (
auto*
const section : sections_) {
1648 if (section->HasBits())
continue;
1649 if (should_add(section)) {
1650 add_to_reordered_sections(section);
1657 auto*
const build_id = Find(Elf::kBuildIdNoteName);
1658 if (build_id !=
nullptr) {
1659 ASSERT(build_id->type == elf::SectionHeaderType::SHT_NOTE);
1660 add_to_reordered_sections(build_id);
1664 add_sections_matching([&](
Section* section) ->
bool {
1665 if (section == build_id)
return false;
1666 return section->IsAllocated() && !section->IsWritable() &&
1667 !section->IsExecutable();
1671 add_sections_matching([](
Section* section) ->
bool {
1672 return section->IsExecutable();
1676 add_sections_matching([](
Section* section) ->
bool {
1677 return section->IsWritable();
1685 add_sections_matching([](
Section* section) ->
bool {
1687 return !section->IsReservedSection() && !section->IsAllocated();
1691 ASSERT_EQUAL(sections_.length(), reordered_sections.length());
1694 sections_.AddArray(reordered_sections);
1701 for (
auto*
const section : sections_) {
1703 section->link = index_map[section->link];
1704 if (
auto*
const table = section->AsSymbolTable()) {
1705 table->UpdateSectionIndices(index_map);
1710 symtab->UpdateSectionIndices(index_map);
1714 if (build_id !=
nullptr) {
1717 new (zone_) Segment(zone_, build_id, elf::ProgramHeaderType::PT_NOTE));
1721 ASSERT(HasSectionNamed(Elf::kDynamicTableName));
1722 auto*
const dynamic = Find(Elf::kDynamicTableName)->AsDynamicTable();
1724 new (zone_) Segment(zone_, dynamic, elf::ProgramHeaderType::PT_DYNAMIC));
1728 auto*
const gnu_stack =
new (zone_) GnuStackSection();
1729 program_table->Add(
new (zone_) Segment(zone_, gnu_stack,
1730 elf::ProgramHeaderType::PT_GNU_STACK));
1732 return program_table;
1735void Elf::Finalize() {
1745 FinalizeDwarfSections();
1749 InitializeSymbolTables();
1754 program_table_ = section_table_->CreateProgramTable(symtab_);
1760 if (type_ == Type::Snapshot) {
1763 for (
auto*
const segment : program_table_->segments()) {
1764 for (
auto*
const section : segment->sections()) {
1773 ElfWriteStream
wrapped(unwrapped_stream_, *
this);
1775 auto write_section = [&](
const Section* section) {
1776 wrapped.Align(section->alignment);
1780 section->file_offset() + section->FileSize());
1786 intptr_t section_index = 1;
1787 for (
auto*
const segment : program_table_->segments()) {
1788 if (segment->type != elf::ProgramHeaderType::PT_LOAD)
continue;
1789 wrapped.Align(segment->Alignment());
1790 for (
auto*
const section : segment->sections()) {
1791 ASSERT(section->IsAllocated());
1792 write_section(section);
1793 if (!section->IsPseudoSection()) {
1799 const auto& sections = section_table_->sections();
1800 for (; section_index < sections.length(); section_index++) {
1801 auto*
const section = sections[section_index];
1802 ASSERT(!section->IsAllocated());
1803 write_section(section);
1806 write_section(section_table_);
1813static constexpr const char* kBuildIdSegmentNames[]{
1819static constexpr intptr_t kBuildIdSegmentNamesLength =
1822static constexpr intptr_t kBuildIdHeaderSize =
1825void Elf::GenerateBuildId() {
1827 ASSERT(section_table_->Find(kBuildIdNoteName) ==
nullptr);
1828 uint32_t
hashes[kBuildIdSegmentNamesLength];
1834 auto*
const text_section = section_table_->Find(kTextName);
1835 if (text_section ==
nullptr)
return;
1836 ASSERT(text_section->IsTextSection());
1837 auto*
const text_bits = text_section->AsBitsContainer();
1838 auto*
const data_section = section_table_->Find(kDataName);
1839 ASSERT(data_section ==
nullptr || data_section->IsDataSection());
1845 bool has_any_text =
false;
1846 for (intptr_t
i = 0;
i < kBuildIdSegmentNamesLength;
i++) {
1847 auto*
const name = kBuildIdSegmentNames[
i];
1850 has_any_text =
true;
1851 }
else if (data_section !=
nullptr) {
1852 hashes[
i] = data_section->AsBitsContainer()->Hash(
name);
1857 if (!has_any_text)
return;
1858 auto const description_bytes =
reinterpret_cast<uint8_t*
>(
hashes);
1859 const size_t description_length =
sizeof(
hashes);
1861 ZoneWriteStream
stream(zone(), kBuildIdHeaderSize + description_length);
1863 stream.WriteFixed<
decltype(elf::Note::description_size)>(description_length);
1868 stream.WriteBytes(description_bytes, description_length);
1869 auto*
const container =
new (zone_) NoteSection();
1870 container->AddPortion(
stream.buffer(),
stream.bytes_written(),
1873 section_table_->Add(container, kBuildIdNoteName);
1876void Elf::ComputeOffsets() {
1877 intptr_t file_offset = 0;
1878 intptr_t memory_offset = 0;
1881 const intptr_t num_sections = section_table_->SectionCount();
1882 GrowableArray<intptr_t> address_map(zone_, num_sections);
1885 auto calculate_section_offsets = [&](
Section* section) {
1887 section->set_file_offset(file_offset);
1888 file_offset += section->FileSize();
1889 if (section->IsAllocated()) {
1890 memory_offset =
Utils::RoundUp(memory_offset, section->alignment);
1891 section->set_memory_offset(memory_offset);
1892 memory_offset += section->MemorySize();
1896 intptr_t section_index = 1;
1897 for (
auto*
const segment : program_table_->segments()) {
1898 if (segment->type != elf::ProgramHeaderType::PT_LOAD)
continue;
1901 memory_offset =
Utils::RoundUp(memory_offset, segment->Alignment());
1902 for (
auto*
const section : segment->sections()) {
1903 ASSERT(section->IsAllocated());
1904 calculate_section_offsets(section);
1905 if (!section->IsPseudoSection()) {
1909 address_map.Add(section->memory_offset());
1916 const auto& sections = section_table_->sections();
1917 for (; section_index < sections.length(); section_index++) {
1918 auto*
const section = sections[section_index];
1919 ASSERT(!section->IsAllocated());
1920 calculate_section_offsets(section);
1926 calculate_section_offsets(section_table_);
1930 for (
auto*
const segment : program_table_->segments()) {
1931 ASSERT(Utils::IsAligned(segment->MemoryOffset(), segment->Alignment()));
1939 for (
auto*
const section : sections) {
1940 if (
auto*
const table = section->AsSymbolTable()) {
1941 table->Finalize(address_map);
1942 }
else if (
auto*
const dynamic = section->AsDynamicTable()) {
1943 dynamic->Finalize();
1949 symtab_->Finalize(address_map);
1953void ElfHeader::Write(ElfWriteStream*
stream)
const {
1956#if defined(TARGET_ARCH_IS_32_BIT)
1961 uint8_t e_ident[16] = {0x7f,
1977 stream->WriteBytes(e_ident, 16);
1981#if defined(TARGET_ARCH_IA32)
1983#elif defined(TARGET_ARCH_X64)
1985#elif defined(TARGET_ARCH_ARM)
1987#elif defined(TARGET_ARCH_ARM64)
1989#elif defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
1992 FATAL(
"Unknown ELF architecture");
1997 stream->WriteOff(program_table_.file_offset());
1998 stream->WriteOff(section_table_.file_offset());
2000#if defined(TARGET_ARCH_ARM)
2009 stream->WriteHalf(
sizeof(elf::ElfHeader));
2010 stream->WriteHalf(program_table_.entry_size);
2011 stream->WriteHalf(program_table_.SegmentCount());
2012 stream->WriteHalf(section_table_.entry_size);
2013 stream->WriteHalf(section_table_.SectionCount());
2014 stream->WriteHalf(
stream->elf().section_table().StringTableIndex());
2017void ProgramTable::Write(ElfWriteStream*
stream)
const {
2018 ASSERT(segments_.length() > 0);
2021 ASSERT(segments_[0]->
type == elf::ProgramHeaderType::PT_PHDR);
2029 bool last_writable =
true;
2030 int non_writable_groups = 0;
2032 for (intptr_t
i = 0;
i < segments_.length();
i++) {
2033 const Segment*
const segment = segments_[
i];
2034 ASSERT(segment->type != elf::ProgramHeaderType::PT_NULL);
2035 ASSERT_EQUAL(
i == 0, segment->type == elf::ProgramHeaderType::PT_PHDR);
2037 if (segment->type == elf::ProgramHeaderType::PT_LOAD) {
2038 if (last_writable && !segment->IsWritable()) {
2039 non_writable_groups++;
2041 last_writable = segment->IsWritable();
2045 segment->WriteProgramHeader(
stream);
2046 const intptr_t
end =
stream->Position();
2053 ASSERT(non_writable_groups <= 1);
2057void SectionTable::Write(ElfWriteStream*
stream)
const {
2058 for (intptr_t
i = 0;
i < sections_.length();
i++) {
2059 const Section*
const section = sections_[
i];
2062 ASSERT(section->link < sections_.length());
2064 section->WriteSectionHeader(
stream);
2065 const intptr_t
end =
stream->Position();
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static sk_sp< GrTextureProxy > wrapped(skiatest::Reporter *reporter, GrRecordingContext *rContext, GrProxyProvider *proxyProvider, SkBackingFit fit)
#define DEBUG_ASSERT(cond)
#define ASSERT_EQUAL(expected, actual)
#define RELEASE_ASSERT(cond)
#define COMPILE_ASSERT(expr)
#define ASSERT_NOTNULL(ptr)
static bool IsInt(intptr_t N, T value)
static constexpr T RoundUp(T x, uintptr_t alignment, uintptr_t offset=0)
static uint32_t StringHash(const void *data, int length)
static constexpr bool IsAligned(T x, uintptr_t alignment, uintptr_t offset=0)
static constexpr bool IsPowerOfTwo(T x)
#define kIsolateSnapshotDataAsmSymbol
#define kIsolateSnapshotBssAsmSymbol
#define kIsolateSnapshotInstructionsAsmSymbol
#define kVmSnapshotBssAsmSymbol
#define kVmSnapshotDataAsmSymbol
#define kVmSnapshotInstructionsAsmSymbol
#define kSnapshotBuildIdAsmSymbol
FlutterSemanticsFlag flags
Dart_NativeFunction function
static int SizeInBytes(Dart_TypedData_Type type)
static constexpr intptr_t kWordSize
static constexpr intptr_t ELFCLASS64
static constexpr intptr_t STT_SECTION
static constexpr intptr_t SHN_UNDEF
static constexpr intptr_t EF_ARM_ABI_FLOAT_SOFT
static constexpr intptr_t ELFOSABI_SYSV
static constexpr intptr_t STB_GLOBAL
static constexpr intptr_t PF_R
static constexpr intptr_t PF_X
static constexpr intptr_t STN_UNDEF
static constexpr intptr_t ET_DYN
static constexpr intptr_t EM_X86_64
static constexpr intptr_t EM_386
static constexpr intptr_t ELFCLASS32
static constexpr intptr_t EM_RISCV
static constexpr intptr_t EM_AARCH64
constexpr decltype(Symbol::info) SymbolInfo(intptr_t binding, intptr_t type)
static constexpr intptr_t STB_LOCAL
static constexpr intptr_t SHF_EXECINSTR
static constexpr intptr_t SHF_WRITE
static constexpr intptr_t PF_W
static constexpr const char ELF_NOTE_GNU[]
static constexpr intptr_t ELFDATA2LSB
static constexpr intptr_t EF_ARM_ABI_FLOAT_HARD
static constexpr intptr_t STT_NOTYPE
static constexpr intptr_t EF_ARM_ABI
static constexpr intptr_t EM_ARM
static constexpr intptr_t EV_CURRENT
static constexpr intptr_t SHF_ALLOC
static constexpr intptr_t STT_OBJECT
def link(from_root, to_root)
static constexpr int kSavedCallerPcSlotFromFp
static constexpr int kSavedCallerFpSlotFromFp
constexpr intptr_t kInt64Size
constexpr intptr_t kBitsPerByte
Register ConcreteRegister(LinkRegister)
static constexpr int kCallerSpSlotFromFp
constexpr intptr_t kInt32Size
static uint32_t Hash(uint32_t key)
constexpr intptr_t kWordSize
static void RoundUp(Vector< char > buffer, int *length, int *decimal_point)
DEF_SWITCHES_START aot vmservice shared library name
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static bool IsExecutable(std::initializer_list< FileMapping::Protection > protection_flags)
static bool IsWritable(std::initializer_list< FileMapping::Protection > protection_flags)
void Initialize(zx::channel directory_request, std::optional< zx::eventpair > view_ref)
Initializes Dart bindings for the Fuchsia application model.
static constexpr Value kNoValue
#define ARRAY_SIZE(array)