Revert "[vm/compiler] Add symbols for read-only data when requested."

This reverts commit 286326f834.

Reason for revert: Reverting for the regressions mentioned in https://github.com/flutter/flutter/issues/108378

Original change's description:
> [vm/compiler] Add symbols for read-only data when requested.
>
> Symbols for non-clustered objects in the read-only data section are
> now added to the static symbol tables for unstripped snapshots and
> separate debugging information.
>
> In DEBUG mode, the name for a non-String read-only data object also
> includes the name of the parent object.
>
> TEST=vm/dart{,_2}/readonly_data_symbols
>
> Change-Id: I623b023138aeca0580bc76392882eac5686f8f50
> Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-dwarf-linux-product-x64-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-nnbd-linux-release-x64-try,vm-kernel-precomp-nnbd-mac-release-arm64-try
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/251104
> Reviewed-by: Ryan Macnak <rmacnak@google.com>
> Commit-Queue: Tess Strickland <sstrickl@google.com>

# Not skipping CQ checks because original CL landed > 1 day ago.

Change-Id: I82bdabf07c137fbabe7b4c45bdf23011350c3d87
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-dwarf-linux-product-x64-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-nnbd-linux-release-x64-try,vm-kernel-precomp-nnbd-mac-release-arm64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/252801
Reviewed-by: Tess Strickland <sstrickl@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Zach Anderson <zra@google.com>
This commit is contained in:
Zach Anderson 2022-07-27 13:30:28 +00:00 committed by Commit Bot
parent 27dc7de6d6
commit 3b8817e7fc
11 changed files with 129 additions and 581 deletions

View file

@ -1,7 +1,3 @@
## 0.5.1
- Exported more ELF utilities for use in Dart tests.
## 0.5.0 ## 0.5.0
- Require Dart >= 2.17 (enhanced enum support) - Require Dart >= 2.17 (enhanced enum support)

View file

@ -8,12 +8,4 @@ export 'src/constants.dart'
isolateSymbolName, isolateSymbolName,
vmDataSymbolName, vmDataSymbolName,
vmSymbolName; vmSymbolName;
export 'src/elf.dart' export 'src/elf.dart' show DynamicTable, DynamicTableTag, Elf, Section, Symbol;
show
DynamicTable,
DynamicTableTag,
Elf,
Section,
Symbol,
SymbolBinding,
SymbolType;

View file

@ -696,19 +696,16 @@ class StringTable extends Section implements DwarfContainerStringTable {
} }
} }
/// An enumeration of recognized symbol binding values used by the ELF format.
enum SymbolBinding { enum SymbolBinding {
STB_LOCAL, STB_LOCAL,
STB_GLOBAL, STB_GLOBAL,
STB_WEAK, STB_WEAK,
} }
/// An enumeration of recognized symbol types used by the ELF format.
enum SymbolType { enum SymbolType {
STT_NOTYPE, STT_NOTYPE,
STT_OBJECT, STT_OBJECT,
STT_FUNC, STT_FUNC,
STT_SECTION,
} }
enum SymbolVisibility { enum SymbolVisibility {
@ -1009,17 +1006,6 @@ class Elf implements DwarfContainer {
return null; 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 /// Reverse lookup of the static symbol that contains the given virtual
/// address. Returns null if no static symbol matching the address is found. /// address. Returns null if no static symbol matching the address is found.
@override @override
@ -1042,17 +1028,6 @@ class Elf implements DwarfContainer {
return bestSym; 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]. /// Creates an [Elf] from the data pointed to by [reader].
/// ///
/// After succesful completion, the [endian] and [wordSize] fields of the /// After succesful completion, the [endian] and [wordSize] fields of the

View file

@ -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');
}
}
}

View file

@ -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');
}
}
}

View file

@ -7288,11 +7288,7 @@ void Serializer::TraceDataOffset(uint32_t offset) {
} }
uint32_t Serializer::GetDataOffset(ObjectPtr object) const { uint32_t Serializer::GetDataOffset(ObjectPtr object) const {
#if defined(SNAPSHOT_BACKTRACE)
return image_writer_->GetDataOffsetFor(object, ParentOf(object));
#else
return image_writer_->GetDataOffsetFor(object); return image_writer_->GetDataOffsetFor(object);
#endif
} }
intptr_t Serializer::GetDataSize() const { intptr_t Serializer::GetDataSize() const {
@ -7397,16 +7393,7 @@ void Serializer::UnexpectedObject(ObjectPtr raw_object, const char* message) {
} }
#if defined(SNAPSHOT_BACKTRACE) #if defined(SNAPSHOT_BACKTRACE)
ObjectPtr Serializer::ParentOf(ObjectPtr 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) {
return parent_pairs_[i + 1]->ptr();
}
}
return Object::null();
}
ObjectPtr Serializer::ParentOf(const Object& object) const {
for (intptr_t i = 0; i < parent_pairs_.length(); i += 2) { for (intptr_t i = 0; i < parent_pairs_.length(); i += 2) {
if (parent_pairs_[i]->ptr() == object.ptr()) { if (parent_pairs_[i]->ptr() == object.ptr()) {
return parent_pairs_[i + 1]->ptr(); return parent_pairs_[i + 1]->ptr();

View file

@ -19,6 +19,10 @@
#include "vm/snapshot.h" #include "vm/snapshot.h"
#include "vm/version.h" #include "vm/version.h"
#if defined(DEBUG)
#define SNAPSHOT_BACKTRACE
#endif
namespace dart { namespace dart {
// For full snapshots, we use a clustered snapshot format that trades longer // For full snapshots, we use a clustered snapshot format that trades longer
@ -240,8 +244,7 @@ class Serializer : public ThreadStackResource {
void UnexpectedObject(ObjectPtr object, const char* message); void UnexpectedObject(ObjectPtr object, const char* message);
#if defined(SNAPSHOT_BACKTRACE) #if defined(SNAPSHOT_BACKTRACE)
ObjectPtr ParentOf(ObjectPtr object) const; ObjectPtr ParentOf(const Object& object);
ObjectPtr ParentOf(const Object& object) const;
#endif #endif
SerializationCluster* NewClusterForClass(intptr_t cid, bool is_canonical); SerializationCluster* NewClusterForClass(intptr_t cid, bool is_canonical);

View file

@ -179,9 +179,6 @@ ImageWriter::ImageWriter(Thread* t)
next_text_offset_(0), next_text_offset_(0),
objects_(), objects_(),
instructions_(), instructions_(),
#if defined(DART_PRECOMPILER)
namer_(t->zone()),
#endif
image_type_(TagObjectTypeAsReadOnly(zone_, "Image")), image_type_(TagObjectTypeAsReadOnly(zone_, "Image")),
instructions_section_type_( instructions_section_type_(
TagObjectTypeAsReadOnly(zone_, "InstructionsSection")), TagObjectTypeAsReadOnly(zone_, "InstructionsSection")),
@ -289,20 +286,11 @@ intptr_t ImageWriter::SizeInSnapshot(ObjectPtr raw_object) {
} }
} }
#if defined(SNAPSHOT_BACKTRACE)
uint32_t ImageWriter::GetDataOffsetFor(ObjectPtr raw_object,
ObjectPtr raw_parent) {
#else
uint32_t ImageWriter::GetDataOffsetFor(ObjectPtr raw_object) { uint32_t ImageWriter::GetDataOffsetFor(ObjectPtr raw_object) {
#endif
const intptr_t snap_size = SizeInSnapshot(raw_object); const intptr_t snap_size = SizeInSnapshot(raw_object);
const intptr_t offset = next_data_offset_; const intptr_t offset = next_data_offset_;
next_data_offset_ += snap_size; next_data_offset_ += snap_size;
#if defined(SNAPSHOT_BACKTRACE)
objects_.Add(ObjectData(raw_object, raw_parent));
#else
objects_.Add(ObjectData(raw_object)); objects_.Add(ObjectData(raw_object));
#endif
return offset; return offset;
} }
@ -467,11 +455,8 @@ void ImageWriter::Write(NonStreamingWriteStream* clustered_stream, bool vm) {
heap->SetObjectId(data.insns_->ptr(), 0); heap->SetObjectId(data.insns_->ptr(), 0);
} }
for (auto& data : objects_) { for (auto& data : objects_) {
if (data.is_object()) { if (data.is_object) {
data.obj = &Object::Handle(zone_, data.raw_obj); 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 @@ void ImageWriter::Write(NonStreamingWriteStream* clustered_stream, bool vm) {
// to string objects. String is used for simplicity as a bit container, // to string objects. String is used for simplicity as a bit container,
// can't use TypedData because it has an internal pointer (data_) field. // can't use TypedData because it has an internal pointer (data_) field.
for (auto& data : objects_) { for (auto& data : objects_) {
if (!data.is_object()) { if (!data.is_object) {
const auto bytes = data.bytes; const auto bytes = data.bytes;
data.obj = &Object::Handle( data.obj = &Object::Handle(
zone_, OneByteString::New(bytes.buf, bytes.length, Heap::kOld)); zone_, OneByteString::New(bytes.buf, bytes.length, Heap::kOld));
#if defined(SNAPSHOT_BACKTRACE) data.is_object = true;
data.parent = &Object::null_object();
#endif
data.set_is_object(true);
String::Cast(*data.obj).Hash(); String::Cast(*data.obj).Hash();
free(bytes.buf); free(bytes.buf);
} }
@ -507,8 +489,13 @@ void ImageWriter::Write(NonStreamingWriteStream* clustered_stream, bool vm) {
} }
void ImageWriter::WriteROData(NonStreamingWriteStream* stream, bool vm) { 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. // Heap page starts here.
intptr_t section_start = stream->Position(); intptr_t section_start = stream->Position();
stream->WriteWord(next_data_offset_); // Data length. stream->WriteWord(next_data_offset_); // Data length.
@ -518,20 +505,20 @@ void ImageWriter::WriteROData(NonStreamingWriteStream* stream, bool vm) {
ASSERT_EQUAL(stream->Position() - section_start, Image::kHeaderSize); ASSERT_EQUAL(stream->Position() - section_start, Image::kHeaderSize);
#if defined(DART_PRECOMPILER) #if defined(DART_PRECOMPILER)
if (profile_writer_ != nullptr) { if (profile_writer_ != nullptr) {
// Attribute the Image header to the artificial root. const intptr_t end_position = stream->Position();
profile_writer_->AttributeBytesTo( profile_writer_->AttributeBytesTo(
V8SnapshotProfileWriter::kArtificialRootId, Image::kHeaderSize); V8SnapshotProfileWriter::kArtificialRootId,
end_position - start_position);
} }
#endif #endif
// Heap page objects start here. // Heap page objects start here.
for (auto entry : objects_) { for (auto entry : objects_) {
ASSERT(entry.is_object()); ASSERT(entry.is_object);
const Object& obj = *entry.obj; const Object& obj = *entry.obj;
#if defined(DART_PRECOMPILER) #if defined(DART_PRECOMPILER)
AutoTraceImage(obj, section_start, stream); AutoTraceImage(obj, section_start, stream);
const char* object_name = namer_.SnapshotNameFor(entry);
#endif #endif
auto const object_start = stream->Position(); auto const object_start = stream->Position();
@ -581,9 +568,6 @@ void ImageWriter::WriteROData(NonStreamingWriteStream* stream, bool vm) {
} }
stream->Align(compiler::target::ObjectAlignment::kObjectAlignment); stream->Align(compiler::target::ObjectAlignment::kObjectAlignment);
ASSERT_EQUAL(stream->Position() - object_start, SizeInSnapshot(obj)); 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 @@ void ImageWriter::WriteText(bool vm) {
#if defined(DART_PRECOMPILER) #if defined(DART_PRECOMPILER)
PcDescriptors& descriptors = PcDescriptors::Handle(zone_); PcDescriptors& descriptors = PcDescriptors::Handle(zone_);
SnapshotTextObjectNamer namer(zone_);
#endif #endif
ASSERT(offset_space_ != IdSpace::kSnapshot); ASSERT(offset_space_ != IdSpace::kSnapshot);
@ -797,7 +782,10 @@ void ImageWriter::WriteText(bool vm) {
ASSERT_EQUAL(data.text_offset_, text_offset); ASSERT_EQUAL(data.text_offset_, text_offset);
#if defined(DART_PRECOMPILER) #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) { if (profile_writer_ != nullptr) {
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset); const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
@ -1118,7 +1106,7 @@ void AssemblyImageWriter::Finalize() {
} }
} }
static void AddAssemblerIdentifier(BaseTextBuffer* printer, const char* label) { static void AddAssemblerIdentifier(ZoneTextBuffer* printer, const char* label) {
ASSERT(label[0] != '.'); ASSERT(label[0] != '.');
if (label[0] == 'L' && printer->length() == 0) { if (label[0] == 'L' && printer->length() == 0) {
// Assembler treats labels starting with `L` as local which can cause // Assembler treats labels starting with `L` as local which can cause
@ -1171,89 +1159,47 @@ static void AddAssemblerIdentifier(BaseTextBuffer* printer, const char* label) {
} }
} }
void ImageWriter::SnapshotTextObjectNamer::AddNonUniqueNameFor( const char* SnapshotTextObjectNamer::SnapshotNameFor(intptr_t code_index,
BaseTextBuffer* buffer, const Code& code) {
const Object& object) { ASSERT(!code.IsNull());
if (object.IsCode()) { owner_ = code.owner();
const Code& code = Code::Cast(object); if (owner_.IsNull()) {
owner_ = WeakSerializationReference::Unwrap(code.owner()); insns_ = code.instructions();
if (owner_.IsNull()) { const char* name = StubCode::NameOfStub(insns_.EntryPoint());
buffer->AddString("Stub_"); ASSERT(name != nullptr);
insns_ = code.instructions(); return OS::SCreate(zone_, "Stub_%s", name);
const char* name = StubCode::NameOfStub(insns_.EntryPoint()); }
ASSERT(name != nullptr); // The weak reference to the Code's owner should never have been removed via
buffer->AddString(name); // an intermediate serialization, since WSRs are only introduced during
} else { // precompilation.
if (owner_.IsClass()) { owner_ = WeakSerializationReference::Unwrap(owner_);
buffer->AddString("AllocationStub_"); ASSERT(!owner_.IsNull());
} else if (!owner_.IsAbstractType() && !owner_.IsFunction()) { ZoneTextBuffer printer(zone_);
// Double-check that we didn't get an invalid owner for the Code object. if (owner_.IsClass()) {
UNREACHABLE(); const char* name = Class::Cast(owner_).ScrubbedNameCString();
} printer.AddString("AllocationStub_");
AddNonUniqueNameFor(buffer, owner_); AddAssemblerIdentifier(&printer, name);
} } else if (owner_.IsAbstractType()) {
} else if (object.IsClass()) { const char* name = namer_.StubNameForType(AbstractType::Cast(owner_));
const char* name = Class::Cast(object).ScrubbedNameCString(); printer.AddString(name);
AddAssemblerIdentifier(buffer, name); } else if (owner_.IsFunction()) {
} else if (object.IsAbstractType()) { const char* name = Function::Cast(owner_).QualifiedScrubbedNameCString();
namer_.WriteStubNameForTypeTo(buffer, AbstractType::Cast(object)); AddAssemblerIdentifier(&printer, name);
} 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");
}
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
printer.Printf("_%" Pd, code_index);
return printer.buffer();
} }
const char* ImageWriter::SnapshotTextObjectNamer::SnapshotNameFor( const char* SnapshotTextObjectNamer::SnapshotNameFor(
const InstructionsData& data) { intptr_t index,
ZoneTextBuffer printer(zone_); const ImageWriter::InstructionsData& data) {
if (data.trampoline_bytes != nullptr) { if (data.trampoline_bytes != nullptr) {
printer.AddString("Trampoline"); return OS::SCreate(zone_, "Trampoline_%" Pd "", index);
} else {
AddNonUniqueNameFor(&printer, *data.code_);
} }
printer.Printf("_%" Pd, nonce_++); return SnapshotNameFor(index, *data.code_);
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();
} }
void AssemblyImageWriter::WriteBss(bool vm) { void AssemblyImageWriter::WriteBss(bool vm) {
@ -1269,35 +1215,12 @@ void AssemblyImageWriter::WriteBss(bool vm) {
void AssemblyImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream, void AssemblyImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
bool vm) { bool vm) {
ImageWriter::WriteROData(clustered_stream, vm);
if (!EnterSection(ProgramSection::Data, vm, ImageWriter::kRODataAlignment)) { if (!EnterSection(ProgramSection::Data, vm, ImageWriter::kRODataAlignment)) {
return; return;
} }
// The clustered stream already has some data on it from the serializer, so WriteBytes(clustered_stream->buffer(), clustered_stream->bytes_written());
// make sure that the read-only objects start at the appropriate alignment ExitSection(ProgramSection::Data, vm, clustered_stream->bytes_written());
// 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);
} }
bool AssemblyImageWriter::EnterSection(ProgramSection section, bool AssemblyImageWriter::EnterSection(ProgramSection section,
@ -1317,14 +1240,10 @@ bool AssemblyImageWriter::EnterSection(ProgramSection section,
global_symbol = true; global_symbol = true;
break; break;
case ProgramSection::Data: case ProgramSection::Data:
// We create a SymbolData array even if there is no debug_elf_ because we if (debug_elf_ != nullptr) {
// may be writing RO data symbols, and RO data is written in two steps: current_symbols_ =
// 1. Serializing the read-only data objects to the clustered stream new (zone_) ZoneGrowableArray<Elf::SymbolData>(zone_, 0);
// 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 defined(DART_TARGET_OS_LINUX) || defined(DART_TARGET_OS_ANDROID) || \ #if defined(DART_TARGET_OS_LINUX) || defined(DART_TARGET_OS_ANDROID) || \
defined(DART_TARGET_OS_FUCHSIA) defined(DART_TARGET_OS_FUCHSIA)
assembly_stream_->WriteString(".section .rodata\n"); assembly_stream_->WriteString(".section .rodata\n");
@ -1462,12 +1381,6 @@ void AssemblyImageWriter::AddCodeSymbol(const Code& code,
assembly_stream_->Printf("%s:\n", symbol); 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() { void AssemblyImageWriter::FrameUnwindPrologue() {
// Creates DWARF's .debug_frame // Creates DWARF's .debug_frame
// CFI = Call frame information // CFI = Call frame information
@ -1591,22 +1504,11 @@ void BlobImageWriter::WriteBss(bool vm) {
void BlobImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream, void BlobImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
bool vm) { bool vm) {
#if defined(DART_PRECOMPILER) ImageWriter::WriteROData(clustered_stream, vm);
const intptr_t start_position = clustered_stream->Position(); current_section_stream_ = clustered_stream;
#endif
current_section_stream_ = ASSERT_NOTNULL(clustered_stream);
if (!EnterSection(ProgramSection::Data, vm, ImageWriter::kRODataAlignment)) { if (!EnterSection(ProgramSection::Data, vm, ImageWriter::kRODataAlignment)) {
return; 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()); ExitSection(ProgramSection::Data, vm, clustered_stream->bytes_written());
} }
@ -1618,6 +1520,7 @@ bool BlobImageWriter::EnterSection(ProgramSection section,
ASSERT(current_relocations_ == nullptr); ASSERT(current_relocations_ == nullptr);
ASSERT(current_symbols_ == nullptr); ASSERT(current_symbols_ == nullptr);
#endif #endif
// For now, we set current_section_stream_ in ::WriteData.
ASSERT(section == ProgramSection::Data || current_section_stream_ == nullptr); ASSERT(section == ProgramSection::Data || current_section_stream_ == nullptr);
ASSERT(current_section_symbol_ == nullptr); ASSERT(current_section_symbol_ == nullptr);
switch (section) { switch (section) {
@ -1632,8 +1535,6 @@ bool BlobImageWriter::EnterSection(ProgramSection section,
#endif #endif
break; break;
case ProgramSection::Data: case ProgramSection::Data:
// The stream to use is passed into WriteROData and set there.
ASSERT(current_section_stream_ != nullptr);
#if defined(DART_PRECOMPILER) #if defined(DART_PRECOMPILER)
current_relocations_ = current_relocations_ =
new (zone_) ZoneGrowableArray<Elf::Relocation>(zone_, 0); new (zone_) ZoneGrowableArray<Elf::Relocation>(zone_, 0);
@ -1713,12 +1614,6 @@ void BlobImageWriter::AddCodeSymbol(const Code& code,
debug_elf_->dwarf()->AddCode(code, symbol); 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_PRECOMPILER)
#endif // !defined(DART_PRECOMPILED_RUNTIME) #endif // !defined(DART_PRECOMPILED_RUNTIME)

View file

@ -22,10 +22,6 @@
#include "vm/type_testing_stubs.h" #include "vm/type_testing_stubs.h"
#include "vm/v8_snapshot_writer.h" #include "vm/v8_snapshot_writer.h"
#if defined(DEBUG)
#define SNAPSHOT_BACKTRACE
#endif
namespace dart { namespace dart {
// Forward declarations. // Forward declarations.
@ -274,11 +270,7 @@ class ImageWriter : public ValueObject {
offset_space_ == IdSpace::kIsolateText; offset_space_ == IdSpace::kIsolateText;
} }
int32_t GetTextOffsetFor(InstructionsPtr instructions, CodePtr code); 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); uint32_t GetDataOffsetFor(ObjectPtr raw_object);
#endif
uint32_t AddBytesToData(uint8_t* bytes, intptr_t length); uint32_t AddBytesToData(uint8_t* bytes, intptr_t length);
@ -364,27 +356,10 @@ class ImageWriter : public ValueObject {
}; };
struct ObjectData { 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) explicit ObjectData(ObjectPtr raw_obj)
: raw_obj(raw_obj), : raw_obj(raw_obj), is_object(true) {}
flags(IsObjectField::encode(true) |
IsOriginalObjectField::encode(true)) {}
ObjectData(uint8_t* buf, intptr_t length) ObjectData(uint8_t* buf, intptr_t length)
: bytes({buf, length}), : bytes({buf, length}), is_object(false) {}
flags(IsObjectField::encode(false) |
IsOriginalObjectField::encode(false)) {}
#endif
union { union {
struct { struct {
@ -394,26 +369,7 @@ class ImageWriter : public ValueObject {
ObjectPtr raw_obj; ObjectPtr raw_obj;
const Object* obj; const Object* obj;
}; };
#if defined(SNAPSHOT_BACKTRACE) bool is_object;
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>;
}; };
// Methods abstracting out the particulars of the underlying concrete writer. // Methods abstracting out the particulars of the underlying concrete writer.
@ -459,10 +415,6 @@ class ImageWriter : public ValueObject {
virtual void AddCodeSymbol(const Code& code, virtual void AddCodeSymbol(const Code& code,
const char* symbol, const char* symbol,
intptr_t section_offset) = 0; 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. // Overloaded convenience versions of the above virtual methods.
@ -490,47 +442,6 @@ class ImageWriter : public ValueObject {
GrowableArray<ObjectData> objects_; GrowableArray<ObjectData> objects_;
GrowableArray<InstructionsData> instructions_; 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; IdSpace offset_space_ = IdSpace::kSnapshot;
V8SnapshotProfileWriter* profile_writer_ = nullptr; V8SnapshotProfileWriter* profile_writer_ = nullptr;
const char* const image_type_; const char* const image_type_;
@ -538,8 +449,12 @@ class ImageWriter : public ValueObject {
const char* const instructions_type_; const char* const instructions_type_;
const char* const trampoline_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> template <class T>
friend class TraceImageObjectScope; friend class TraceImageObjectScope;
friend class SnapshotTextObjectNamer; // For InstructionsData.
private: private:
static intptr_t SizeInSnapshotForBytes(intptr_t length); static intptr_t SizeInSnapshotForBytes(intptr_t length);
@ -588,6 +503,32 @@ class TraceImageObjectScope : ValueObject {
DISALLOW_COPY_AND_ASSIGN(TraceImageObjectScope); 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 { class AssemblyImageWriter : public ImageWriter {
public: public:
AssemblyImageWriter(Thread* thread, AssemblyImageWriter(Thread* thread,
@ -622,7 +563,6 @@ class AssemblyImageWriter : public ImageWriter {
virtual void AddCodeSymbol(const Code& code, virtual void AddCodeSymbol(const Code& code,
const char* symbol, const char* symbol,
intptr_t offset); intptr_t offset);
virtual void AddDataSymbol(const char* symbol, intptr_t offset, size_t size);
BaseWriteStream* const assembly_stream_; BaseWriteStream* const assembly_stream_;
Dwarf* const assembly_dwarf_; Dwarf* const assembly_dwarf_;
@ -631,8 +571,8 @@ class AssemblyImageWriter : public ImageWriter {
// Used in Relocation to output "(.)" for relocations involving the current // Used in Relocation to output "(.)" for relocations involving the current
// section position and creating local symbols in AddCodeSymbol. // section position and creating local symbols in AddCodeSymbol.
const char* current_section_symbol_ = nullptr; const char* current_section_symbol_ = nullptr;
// Used for creating local symbols for code and data objects in the // Used for creating local symbols for code objects in the debugging info,
// debugging info, if separately written. // if separately written.
ZoneGrowableArray<Elf::SymbolData>* current_symbols_ = nullptr; ZoneGrowableArray<Elf::SymbolData>* current_symbols_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(AssemblyImageWriter); DISALLOW_COPY_AND_ASSIGN(AssemblyImageWriter);
@ -676,7 +616,6 @@ class BlobImageWriter : public ImageWriter {
virtual void AddCodeSymbol(const Code& code, virtual void AddCodeSymbol(const Code& code,
const char* symbol, const char* symbol,
intptr_t offset); 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 // Set on section entrance to a new array containing the relocations for the
// current section. // current section.

View file

@ -14,7 +14,6 @@
#include "vm/stub_code.h" #include "vm/stub_code.h"
#include "vm/timeline.h" #include "vm/timeline.h"
#include "vm/type_testing_stubs.h" #include "vm/type_testing_stubs.h"
#include "vm/zone_text_buffer.h"
#if !defined(DART_PRECOMPILED_RUNTIME) #if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/backend/flow_graph_compiler.h" #include "vm/compiler/backend/flow_graph_compiler.h"
@ -33,60 +32,57 @@ TypeTestingStubNamer::TypeTestingStubNamer()
const char* TypeTestingStubNamer::StubNameForType( const char* TypeTestingStubNamer::StubNameForType(
const AbstractType& type) const { const AbstractType& type) const {
ZoneTextBuffer buffer(Thread::Current()->zone()); Zone* Z = Thread::Current()->zone();
WriteStubNameForTypeTo(&buffer, type); return OS::SCreate(Z, "TypeTestingStub_%s", StringifyType(type));
return buffer.buffer();
} }
void TypeTestingStubNamer::WriteStubNameForTypeTo( const char* TypeTestingStubNamer::StringifyType(
BaseTextBuffer* buffer,
const AbstractType& type) const { const AbstractType& type) const {
buffer->AddString("TypeTestingStub_");
StringifyTypeTo(buffer, type);
}
void TypeTestingStubNamer::StringifyTypeTo(BaseTextBuffer* buffer,
const AbstractType& type) const {
NoSafepointScope no_safepoint; NoSafepointScope no_safepoint;
Zone* Z = Thread::Current()->zone();
if (type.IsType()) { if (type.IsType()) {
const intptr_t cid = Type::Cast(type).type_class_id(); const intptr_t cid = Type::Cast(type).type_class_id();
ClassTable* class_table = IsolateGroup::Current()->class_table(); ClassTable* class_table = IsolateGroup::Current()->class_table();
klass_ = class_table->At(cid); klass_ = class_table->At(cid);
ASSERT(!klass_.IsNull()); ASSERT(!klass_.IsNull());
const char* curl = "";
lib_ = klass_.library(); lib_ = klass_.library();
if (!lib_.IsNull()) { if (!lib_.IsNull()) {
string_ = lib_.url(); string_ = lib_.url();
buffer->AddString(string_.ToCString()); curl = OS::SCreate(Z, "%s_", string_.ToCString());
} else { } else {
buffer->Printf("nolib%" Pd "_", nonce_++); static std::atomic<intptr_t> counter = 0;
curl = OS::SCreate(Z, "nolib%" Pd "_", counter++);
} }
buffer->AddString("_"); const char* concatenated = AssemblerSafeName(
buffer->AddString(klass_.ScrubbedNameCString()); OS::SCreate(Z, "%s_%s", curl, klass_.ScrubbedNameCString()));
const intptr_t type_parameters = klass_.NumTypeParameters(); const intptr_t type_parameters = klass_.NumTypeParameters();
auto& type_arguments = TypeArguments::Handle(type.arguments()); auto& type_arguments = TypeArguments::Handle();
if (!type_arguments.IsNull() && type_parameters > 0) { if (type.arguments() != TypeArguments::null() && type_parameters > 0) {
type_arguments = type.arguments(); type_arguments = type.arguments();
ASSERT(type_arguments.Length() >= type_parameters); ASSERT(type_arguments.Length() >= type_parameters);
const intptr_t length = type_arguments.Length(); const intptr_t length = type_arguments.Length();
for (intptr_t i = 0; i < type_parameters; ++i) { for (intptr_t i = 0; i < type_parameters; ++i) {
type_ = type_arguments.TypeAt(length - type_parameters + i); type_ = type_arguments.TypeAt(length - type_parameters + i);
buffer->AddString("__"); concatenated =
StringifyTypeTo(buffer, type_); OS::SCreate(Z, "%s__%s", concatenated, StringifyType(type_));
} }
} }
return concatenated;
} else if (type.IsTypeParameter()) { } else if (type.IsTypeParameter()) {
buffer->AddString(TypeParameter::Cast(type).CanonicalNameCString()); return AssemblerSafeName(
OS::SCreate(Z, "%s", TypeParameter::Cast(type).CanonicalNameCString()));
} else { } else {
buffer->AddString(type.ToCString()); return AssemblerSafeName(OS::SCreate(Z, "%s", type.ToCString()));
} }
MakeNameAssemblerSafe(buffer);
} }
void TypeTestingStubNamer::MakeNameAssemblerSafe(BaseTextBuffer* buffer) { const char* TypeTestingStubNamer::AssemblerSafeName(char* cname) {
char* cursor = buffer->buffer(); char* cursor = cname;
while (*cursor != '\0') { while (*cursor != '\0') {
char c = *cursor; char c = *cursor;
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
@ -95,6 +91,7 @@ void TypeTestingStubNamer::MakeNameAssemblerSafe(BaseTextBuffer* buffer) {
} }
cursor++; cursor++;
} }
return cname;
} }
CodePtr TypeTestingStubGenerator::DefaultCodeForType( CodePtr TypeTestingStubGenerator::DefaultCodeForType(

View file

@ -24,19 +24,15 @@ class TypeTestingStubNamer {
// //
// (only during dart_boostrap). // (only during dart_boostrap).
const char* StubNameForType(const AbstractType& type) const; const char* StubNameForType(const AbstractType& type) const;
void WriteStubNameForTypeTo(BaseTextBuffer* buffer,
const AbstractType& type) const;
private: private:
void StringifyTypeTo(BaseTextBuffer* buffer, const AbstractType& type) const; const char* StringifyType(const AbstractType& type) const;
// Converts the contents of the buffer to an assembly-safe name. static const char* AssemblerSafeName(char* cname);
static void MakeNameAssemblerSafe(BaseTextBuffer* buffer);
Library& lib_; Library& lib_;
Class& klass_; Class& klass_;
AbstractType& type_; AbstractType& type_;
String& string_; String& string_;
mutable intptr_t nonce_ = 0;
}; };
class TypeTestingStubGenerator { class TypeTestingStubGenerator {