mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
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:
parent
27dc7de6d6
commit
3b8817e7fc
|
@ -1,7 +1,3 @@
|
|||
## 0.5.1
|
||||
|
||||
- Exported more ELF utilities for use in Dart tests.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
- Require Dart >= 2.17 (enhanced enum support)
|
||||
|
|
|
@ -8,12 +8,4 @@ export 'src/constants.dart'
|
|||
isolateSymbolName,
|
||||
vmDataSymbolName,
|
||||
vmSymbolName;
|
||||
export 'src/elf.dart'
|
||||
show
|
||||
DynamicTable,
|
||||
DynamicTableTag,
|
||||
Elf,
|
||||
Section,
|
||||
Symbol,
|
||||
SymbolBinding,
|
||||
SymbolType;
|
||||
export 'src/elf.dart' show DynamicTable, DynamicTableTag, Elf, Section, Symbol;
|
||||
|
|
|
@ -696,19 +696,16 @@ class StringTable extends Section implements DwarfContainerStringTable {
|
|||
}
|
||||
}
|
||||
|
||||
/// An enumeration of recognized symbol binding values used by the ELF format.
|
||||
enum SymbolBinding {
|
||||
STB_LOCAL,
|
||||
STB_GLOBAL,
|
||||
STB_WEAK,
|
||||
}
|
||||
|
||||
/// An enumeration of recognized symbol types used by the ELF format.
|
||||
enum SymbolType {
|
||||
STT_NOTYPE,
|
||||
STT_OBJECT,
|
||||
STT_FUNC,
|
||||
STT_SECTION,
|
||||
}
|
||||
|
||||
enum SymbolVisibility {
|
||||
|
@ -1009,17 +1006,6 @@ class Elf implements DwarfContainer {
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Returns an iterable of the symbols in the dynamic symbol table(s).
|
||||
/// The ordering of the symbols is not guaranteed.
|
||||
Iterable<Symbol> get dynamicSymbols sync* {
|
||||
for (final section in namedSections('.dynsym')) {
|
||||
final dynsym = section as SymbolTable;
|
||||
for (final symbol in dynsym.values) {
|
||||
yield symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reverse lookup of the static symbol that contains the given virtual
|
||||
/// address. Returns null if no static symbol matching the address is found.
|
||||
@override
|
||||
|
@ -1042,17 +1028,6 @@ class Elf implements DwarfContainer {
|
|||
return bestSym;
|
||||
}
|
||||
|
||||
/// Returns an iterable of the symbols in the static symbol table(s).
|
||||
/// The ordering of the symbols is not guaranteed.
|
||||
Iterable<Symbol> get staticSymbols sync* {
|
||||
for (final section in namedSections('.symtab')) {
|
||||
final symtab = section as SymbolTable;
|
||||
for (final symbol in symtab.values) {
|
||||
yield symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an [Elf] from the data pointed to by [reader].
|
||||
///
|
||||
/// After succesful completion, the [endian] and [wordSize] fields of the
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7288,11 +7288,7 @@ void Serializer::TraceDataOffset(uint32_t offset) {
|
|||
}
|
||||
|
||||
uint32_t Serializer::GetDataOffset(ObjectPtr object) const {
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
return image_writer_->GetDataOffsetFor(object, ParentOf(object));
|
||||
#else
|
||||
return image_writer_->GetDataOffsetFor(object);
|
||||
#endif
|
||||
}
|
||||
|
||||
intptr_t Serializer::GetDataSize() const {
|
||||
|
@ -7397,16 +7393,7 @@ void Serializer::UnexpectedObject(ObjectPtr raw_object, const char* message) {
|
|||
}
|
||||
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
ObjectPtr Serializer::ParentOf(ObjectPtr object) const {
|
||||
for (intptr_t i = 0; i < parent_pairs_.length(); i += 2) {
|
||||
if (parent_pairs_[i]->ptr() == object) {
|
||||
return parent_pairs_[i + 1]->ptr();
|
||||
}
|
||||
}
|
||||
return Object::null();
|
||||
}
|
||||
|
||||
ObjectPtr Serializer::ParentOf(const Object& object) const {
|
||||
ObjectPtr Serializer::ParentOf(const Object& object) {
|
||||
for (intptr_t i = 0; i < parent_pairs_.length(); i += 2) {
|
||||
if (parent_pairs_[i]->ptr() == object.ptr()) {
|
||||
return parent_pairs_[i + 1]->ptr();
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
#include "vm/snapshot.h"
|
||||
#include "vm/version.h"
|
||||
|
||||
#if defined(DEBUG)
|
||||
#define SNAPSHOT_BACKTRACE
|
||||
#endif
|
||||
|
||||
namespace dart {
|
||||
|
||||
// For full snapshots, we use a clustered snapshot format that trades longer
|
||||
|
@ -240,8 +244,7 @@ class Serializer : public ThreadStackResource {
|
|||
|
||||
void UnexpectedObject(ObjectPtr object, const char* message);
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
ObjectPtr ParentOf(ObjectPtr object) const;
|
||||
ObjectPtr ParentOf(const Object& object) const;
|
||||
ObjectPtr ParentOf(const Object& object);
|
||||
#endif
|
||||
|
||||
SerializationCluster* NewClusterForClass(intptr_t cid, bool is_canonical);
|
||||
|
|
|
@ -179,9 +179,6 @@ ImageWriter::ImageWriter(Thread* t)
|
|||
next_text_offset_(0),
|
||||
objects_(),
|
||||
instructions_(),
|
||||
#if defined(DART_PRECOMPILER)
|
||||
namer_(t->zone()),
|
||||
#endif
|
||||
image_type_(TagObjectTypeAsReadOnly(zone_, "Image")),
|
||||
instructions_section_type_(
|
||||
TagObjectTypeAsReadOnly(zone_, "InstructionsSection")),
|
||||
|
@ -289,20 +286,11 @@ 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) {
|
||||
#endif
|
||||
const intptr_t snap_size = SizeInSnapshot(raw_object);
|
||||
const intptr_t offset = next_data_offset_;
|
||||
next_data_offset_ += snap_size;
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
objects_.Add(ObjectData(raw_object, raw_parent));
|
||||
#else
|
||||
objects_.Add(ObjectData(raw_object));
|
||||
#endif
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
@ -467,11 +455,8 @@ void ImageWriter::Write(NonStreamingWriteStream* clustered_stream, bool vm) {
|
|||
heap->SetObjectId(data.insns_->ptr(), 0);
|
||||
}
|
||||
for (auto& data : objects_) {
|
||||
if (data.is_object()) {
|
||||
if (data.is_object) {
|
||||
data.obj = &Object::Handle(zone_, data.raw_obj);
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
data.parent = &Object::Handle(zone_, data.raw_parent);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,14 +464,11 @@ void ImageWriter::Write(NonStreamingWriteStream* clustered_stream, bool vm) {
|
|||
// to string objects. String is used for simplicity as a bit container,
|
||||
// can't use TypedData because it has an internal pointer (data_) field.
|
||||
for (auto& data : objects_) {
|
||||
if (!data.is_object()) {
|
||||
if (!data.is_object) {
|
||||
const auto bytes = data.bytes;
|
||||
data.obj = &Object::Handle(
|
||||
zone_, OneByteString::New(bytes.buf, bytes.length, Heap::kOld));
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
data.parent = &Object::null_object();
|
||||
#endif
|
||||
data.set_is_object(true);
|
||||
data.is_object = true;
|
||||
String::Cast(*data.obj).Hash();
|
||||
free(bytes.buf);
|
||||
}
|
||||
|
@ -507,8 +489,13 @@ void ImageWriter::Write(NonStreamingWriteStream* clustered_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.
|
||||
|
||||
intptr_t section_start = stream->Position();
|
||||
|
||||
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);
|
||||
#if defined(DART_PRECOMPILER)
|
||||
if (profile_writer_ != nullptr) {
|
||||
// Attribute the Image header to the artificial root.
|
||||
const intptr_t end_position = stream->Position();
|
||||
profile_writer_->AttributeBytesTo(
|
||||
V8SnapshotProfileWriter::kArtificialRootId, Image::kHeaderSize);
|
||||
V8SnapshotProfileWriter::kArtificialRootId,
|
||||
end_position - start_position);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Heap page objects start here.
|
||||
|
||||
for (auto entry : objects_) {
|
||||
ASSERT(entry.is_object());
|
||||
ASSERT(entry.is_object);
|
||||
const Object& obj = *entry.obj;
|
||||
#if defined(DART_PRECOMPILER)
|
||||
AutoTraceImage(obj, section_start, stream);
|
||||
const char* object_name = namer_.SnapshotNameFor(entry);
|
||||
#endif
|
||||
auto const object_start = stream->Position();
|
||||
|
||||
|
@ -581,9 +568,6 @@ void ImageWriter::WriteROData(NonStreamingWriteStream* stream, bool vm) {
|
|||
}
|
||||
stream->Align(compiler::target::ObjectAlignment::kObjectAlignment);
|
||||
ASSERT_EQUAL(stream->Position() - object_start, SizeInSnapshot(obj));
|
||||
#if defined(DART_PRECOMPILER)
|
||||
AddDataSymbol(object_name, object_start, stream->Position() - object_start);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -788,6 +772,7 @@ void ImageWriter::WriteText(bool vm) {
|
|||
|
||||
#if defined(DART_PRECOMPILER)
|
||||
PcDescriptors& descriptors = PcDescriptors::Handle(zone_);
|
||||
SnapshotTextObjectNamer namer(zone_);
|
||||
#endif
|
||||
|
||||
ASSERT(offset_space_ != IdSpace::kSnapshot);
|
||||
|
@ -797,7 +782,10 @@ void ImageWriter::WriteText(bool vm) {
|
|||
ASSERT_EQUAL(data.text_offset_, text_offset);
|
||||
|
||||
#if defined(DART_PRECOMPILER)
|
||||
const char* object_name = namer_.SnapshotNameFor(data);
|
||||
// We won't add trampolines as symbols, so their name need not be unique
|
||||
// across different WriteText() calls.
|
||||
const char* object_name = namer.SnapshotNameFor(
|
||||
is_trampoline ? i : unique_symbol_counter_++, data);
|
||||
|
||||
if (profile_writer_ != nullptr) {
|
||||
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
|
||||
|
@ -1118,7 +1106,7 @@ void AssemblyImageWriter::Finalize() {
|
|||
}
|
||||
}
|
||||
|
||||
static void AddAssemblerIdentifier(BaseTextBuffer* printer, const char* label) {
|
||||
static void AddAssemblerIdentifier(ZoneTextBuffer* printer, const char* label) {
|
||||
ASSERT(label[0] != '.');
|
||||
if (label[0] == 'L' && printer->length() == 0) {
|
||||
// Assembler treats labels starting with `L` as local which can cause
|
||||
|
@ -1171,89 +1159,47 @@ static void AddAssemblerIdentifier(BaseTextBuffer* printer, const char* label) {
|
|||
}
|
||||
}
|
||||
|
||||
void ImageWriter::SnapshotTextObjectNamer::AddNonUniqueNameFor(
|
||||
BaseTextBuffer* buffer,
|
||||
const Object& object) {
|
||||
if (object.IsCode()) {
|
||||
const Code& code = Code::Cast(object);
|
||||
owner_ = WeakSerializationReference::Unwrap(code.owner());
|
||||
const char* SnapshotTextObjectNamer::SnapshotNameFor(intptr_t code_index,
|
||||
const Code& code) {
|
||||
ASSERT(!code.IsNull());
|
||||
owner_ = code.owner();
|
||||
if (owner_.IsNull()) {
|
||||
buffer->AddString("Stub_");
|
||||
insns_ = code.instructions();
|
||||
const char* name = StubCode::NameOfStub(insns_.EntryPoint());
|
||||
ASSERT(name != nullptr);
|
||||
buffer->AddString(name);
|
||||
} else {
|
||||
return OS::SCreate(zone_, "Stub_%s", name);
|
||||
}
|
||||
// The weak reference to the Code's owner should never have been removed via
|
||||
// an intermediate serialization, since WSRs are only introduced during
|
||||
// precompilation.
|
||||
owner_ = WeakSerializationReference::Unwrap(owner_);
|
||||
ASSERT(!owner_.IsNull());
|
||||
ZoneTextBuffer printer(zone_);
|
||||
if (owner_.IsClass()) {
|
||||
buffer->AddString("AllocationStub_");
|
||||
} else if (!owner_.IsAbstractType() && !owner_.IsFunction()) {
|
||||
// Double-check that we didn't get an invalid owner for the Code object.
|
||||
UNREACHABLE();
|
||||
}
|
||||
AddNonUniqueNameFor(buffer, owner_);
|
||||
}
|
||||
} else if (object.IsClass()) {
|
||||
const char* name = Class::Cast(object).ScrubbedNameCString();
|
||||
AddAssemblerIdentifier(buffer, name);
|
||||
} else if (object.IsAbstractType()) {
|
||||
namer_.WriteStubNameForTypeTo(buffer, AbstractType::Cast(object));
|
||||
} else if (object.IsFunction()) {
|
||||
const char* name = Function::Cast(object).QualifiedScrubbedNameCString();
|
||||
AddAssemblerIdentifier(buffer, name);
|
||||
} else if (object.IsCompressedStackMaps()) {
|
||||
buffer->AddString("CompressedStackMaps");
|
||||
} else if (object.IsPcDescriptors()) {
|
||||
buffer->AddString("PcDescriptors");
|
||||
} else if (object.IsCodeSourceMap()) {
|
||||
buffer->AddString("CodeSourceMap");
|
||||
} else if (object.IsString()) {
|
||||
const String& str = String::Cast(object);
|
||||
if (str.IsOneByteString()) {
|
||||
buffer->AddString("OneByteString");
|
||||
} else if (str.IsTwoByteString()) {
|
||||
buffer->AddString("TwoByteString");
|
||||
}
|
||||
const char* name = Class::Cast(owner_).ScrubbedNameCString();
|
||||
printer.AddString("AllocationStub_");
|
||||
AddAssemblerIdentifier(&printer, name);
|
||||
} else if (owner_.IsAbstractType()) {
|
||||
const char* name = namer_.StubNameForType(AbstractType::Cast(owner_));
|
||||
printer.AddString(name);
|
||||
} else if (owner_.IsFunction()) {
|
||||
const char* name = Function::Cast(owner_).QualifiedScrubbedNameCString();
|
||||
AddAssemblerIdentifier(&printer, name);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
printer.Printf("_%" Pd, code_index);
|
||||
return printer.buffer();
|
||||
}
|
||||
|
||||
const char* ImageWriter::SnapshotTextObjectNamer::SnapshotNameFor(
|
||||
const InstructionsData& data) {
|
||||
ZoneTextBuffer printer(zone_);
|
||||
const char* SnapshotTextObjectNamer::SnapshotNameFor(
|
||||
intptr_t index,
|
||||
const ImageWriter::InstructionsData& data) {
|
||||
if (data.trampoline_bytes != nullptr) {
|
||||
printer.AddString("Trampoline");
|
||||
} else {
|
||||
AddNonUniqueNameFor(&printer, *data.code_);
|
||||
return OS::SCreate(zone_, "Trampoline_%" Pd "", index);
|
||||
}
|
||||
printer.Printf("_%" Pd, nonce_++);
|
||||
return printer.buffer();
|
||||
}
|
||||
|
||||
const char* ImageWriter::SnapshotTextObjectNamer::SnapshotNameFor(
|
||||
const ObjectData& data) {
|
||||
ASSERT(data.is_object());
|
||||
ZoneTextBuffer printer(zone_);
|
||||
if (data.is_original_object()) {
|
||||
const Object& obj = *data.obj;
|
||||
AddNonUniqueNameFor(&printer, obj);
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
// It's less useful knowing the parent of a String than other read-only
|
||||
// data objects, and this avoids us having to handle other classes
|
||||
// in AddNonUniqueNameFor.
|
||||
if (!obj.IsString()) {
|
||||
const Object& parent = *data.parent;
|
||||
if (!parent.IsNull()) {
|
||||
printer.AddString("_");
|
||||
AddNonUniqueNameFor(&printer, parent);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
printer.AddString("RawBytes");
|
||||
}
|
||||
printer.Printf("_%" Pd, nonce_++);
|
||||
return printer.buffer();
|
||||
return SnapshotNameFor(index, *data.code_);
|
||||
}
|
||||
|
||||
void AssemblyImageWriter::WriteBss(bool vm) {
|
||||
|
@ -1269,35 +1215,12 @@ void AssemblyImageWriter::WriteBss(bool vm) {
|
|||
|
||||
void AssemblyImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
|
||||
bool vm) {
|
||||
ImageWriter::WriteROData(clustered_stream, vm);
|
||||
if (!EnterSection(ProgramSection::Data, vm, ImageWriter::kRODataAlignment)) {
|
||||
return;
|
||||
}
|
||||
// The clustered stream already has some data on it from the serializer, so
|
||||
// make sure that the read-only objects start at the appropriate alignment
|
||||
// within the stream, as we'll write the entire clustered stream to the
|
||||
// assembly output (which was aligned in EnterSection).
|
||||
const intptr_t start_position = clustered_stream->Position();
|
||||
clustered_stream->Align(ImageWriter::kRODataAlignment);
|
||||
if (profile_writer_ != nullptr) {
|
||||
// Attribute any padding needed to the artificial root.
|
||||
const intptr_t padding = clustered_stream->Position() - start_position;
|
||||
profile_writer_->AttributeBytesTo(
|
||||
V8SnapshotProfileWriter::kArtificialRootId, padding);
|
||||
}
|
||||
// First write the read-only data objects to the clustered stream.
|
||||
ImageWriter::WriteROData(clustered_stream, vm);
|
||||
// Next, write the bytes of the clustered stream (along with any symbols
|
||||
// if appropriate) to the assembly output.
|
||||
const uint8_t* bytes = clustered_stream->buffer();
|
||||
const intptr_t len = clustered_stream->bytes_written();
|
||||
intptr_t last_position = 0;
|
||||
for (const auto& symbol : *current_symbols_) {
|
||||
WriteBytes(bytes + last_position, symbol.offset - last_position);
|
||||
assembly_stream_->Printf("%s:\n", symbol.name);
|
||||
last_position = symbol.offset;
|
||||
}
|
||||
WriteBytes(bytes + last_position, len - last_position);
|
||||
ExitSection(ProgramSection::Data, vm, len);
|
||||
WriteBytes(clustered_stream->buffer(), clustered_stream->bytes_written());
|
||||
ExitSection(ProgramSection::Data, vm, clustered_stream->bytes_written());
|
||||
}
|
||||
|
||||
bool AssemblyImageWriter::EnterSection(ProgramSection section,
|
||||
|
@ -1317,14 +1240,10 @@ bool AssemblyImageWriter::EnterSection(ProgramSection section,
|
|||
global_symbol = true;
|
||||
break;
|
||||
case ProgramSection::Data:
|
||||
// We create a SymbolData array even if there is no debug_elf_ because we
|
||||
// may be writing RO data symbols, and RO data is written in two steps:
|
||||
// 1. Serializing the read-only data objects to the clustered stream
|
||||
// 2. Writing the bytes of the clustered stream to the assembly output.
|
||||
// Thus, we'll need to interleave the symbols with the cluster bytes
|
||||
// during step 2.
|
||||
if (debug_elf_ != nullptr) {
|
||||
current_symbols_ =
|
||||
new (zone_) ZoneGrowableArray<Elf::SymbolData>(zone_, 0);
|
||||
}
|
||||
#if defined(DART_TARGET_OS_LINUX) || defined(DART_TARGET_OS_ANDROID) || \
|
||||
defined(DART_TARGET_OS_FUCHSIA)
|
||||
assembly_stream_->WriteString(".section .rodata\n");
|
||||
|
@ -1462,12 +1381,6 @@ void AssemblyImageWriter::AddCodeSymbol(const Code& code,
|
|||
assembly_stream_->Printf("%s:\n", symbol);
|
||||
}
|
||||
|
||||
void AssemblyImageWriter::AddDataSymbol(const char* symbol,
|
||||
intptr_t offset,
|
||||
size_t size) {
|
||||
current_symbols_->Add({symbol, elf::STT_OBJECT, offset, size});
|
||||
}
|
||||
|
||||
void AssemblyImageWriter::FrameUnwindPrologue() {
|
||||
// Creates DWARF's .debug_frame
|
||||
// CFI = Call frame information
|
||||
|
@ -1591,22 +1504,11 @@ void BlobImageWriter::WriteBss(bool vm) {
|
|||
|
||||
void BlobImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
|
||||
bool vm) {
|
||||
#if defined(DART_PRECOMPILER)
|
||||
const intptr_t start_position = clustered_stream->Position();
|
||||
#endif
|
||||
current_section_stream_ = ASSERT_NOTNULL(clustered_stream);
|
||||
ImageWriter::WriteROData(clustered_stream, vm);
|
||||
current_section_stream_ = clustered_stream;
|
||||
if (!EnterSection(ProgramSection::Data, vm, ImageWriter::kRODataAlignment)) {
|
||||
return;
|
||||
}
|
||||
#if defined(DART_PRECOMPILER)
|
||||
if (profile_writer_ != nullptr) {
|
||||
// Attribute any padding needed to the artificial root.
|
||||
const intptr_t padding = clustered_stream->Position() - start_position;
|
||||
profile_writer_->AttributeBytesTo(
|
||||
V8SnapshotProfileWriter::kArtificialRootId, padding);
|
||||
}
|
||||
#endif
|
||||
ImageWriter::WriteROData(clustered_stream, vm);
|
||||
ExitSection(ProgramSection::Data, vm, clustered_stream->bytes_written());
|
||||
}
|
||||
|
||||
|
@ -1618,6 +1520,7 @@ bool BlobImageWriter::EnterSection(ProgramSection section,
|
|||
ASSERT(current_relocations_ == nullptr);
|
||||
ASSERT(current_symbols_ == nullptr);
|
||||
#endif
|
||||
// For now, we set current_section_stream_ in ::WriteData.
|
||||
ASSERT(section == ProgramSection::Data || current_section_stream_ == nullptr);
|
||||
ASSERT(current_section_symbol_ == nullptr);
|
||||
switch (section) {
|
||||
|
@ -1632,8 +1535,6 @@ bool BlobImageWriter::EnterSection(ProgramSection section,
|
|||
#endif
|
||||
break;
|
||||
case ProgramSection::Data:
|
||||
// The stream to use is passed into WriteROData and set there.
|
||||
ASSERT(current_section_stream_ != nullptr);
|
||||
#if defined(DART_PRECOMPILER)
|
||||
current_relocations_ =
|
||||
new (zone_) ZoneGrowableArray<Elf::Relocation>(zone_, 0);
|
||||
|
@ -1713,12 +1614,6 @@ void BlobImageWriter::AddCodeSymbol(const Code& code,
|
|||
debug_elf_->dwarf()->AddCode(code, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
void BlobImageWriter::AddDataSymbol(const char* symbol,
|
||||
intptr_t offset,
|
||||
size_t size) {
|
||||
current_symbols_->Add({symbol, elf::STT_OBJECT, offset, size});
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILER)
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
|
|
|
@ -22,10 +22,6 @@
|
|||
#include "vm/type_testing_stubs.h"
|
||||
#include "vm/v8_snapshot_writer.h"
|
||||
|
||||
#if defined(DEBUG)
|
||||
#define SNAPSHOT_BACKTRACE
|
||||
#endif
|
||||
|
||||
namespace dart {
|
||||
|
||||
// Forward declarations.
|
||||
|
@ -274,11 +270,7 @@ class ImageWriter : public ValueObject {
|
|||
offset_space_ == IdSpace::kIsolateText;
|
||||
}
|
||||
int32_t GetTextOffsetFor(InstructionsPtr instructions, CodePtr code);
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
uint32_t GetDataOffsetFor(ObjectPtr raw_object, ObjectPtr raw_parent);
|
||||
#else
|
||||
uint32_t GetDataOffsetFor(ObjectPtr raw_object);
|
||||
#endif
|
||||
|
||||
uint32_t AddBytesToData(uint8_t* bytes, intptr_t length);
|
||||
|
||||
|
@ -364,27 +356,10 @@ class ImageWriter : public ValueObject {
|
|||
};
|
||||
|
||||
struct ObjectData {
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
explicit ObjectData(ObjectPtr raw_obj, ObjectPtr raw_parent)
|
||||
: raw_obj(raw_obj),
|
||||
raw_parent(raw_parent),
|
||||
flags(IsObjectField::encode(true) |
|
||||
IsOriginalObjectField::encode(true)) {}
|
||||
ObjectData(uint8_t* buf, intptr_t length)
|
||||
: bytes({buf, length}),
|
||||
raw_parent(Object::null()),
|
||||
flags(IsObjectField::encode(false) |
|
||||
IsOriginalObjectField::encode(false)) {}
|
||||
#else
|
||||
explicit ObjectData(ObjectPtr raw_obj)
|
||||
: raw_obj(raw_obj),
|
||||
flags(IsObjectField::encode(true) |
|
||||
IsOriginalObjectField::encode(true)) {}
|
||||
: raw_obj(raw_obj), is_object(true) {}
|
||||
ObjectData(uint8_t* buf, intptr_t length)
|
||||
: bytes({buf, length}),
|
||||
flags(IsObjectField::encode(false) |
|
||||
IsOriginalObjectField::encode(false)) {}
|
||||
#endif
|
||||
: bytes({buf, length}), is_object(false) {}
|
||||
|
||||
union {
|
||||
struct {
|
||||
|
@ -394,26 +369,7 @@ class ImageWriter : public ValueObject {
|
|||
ObjectPtr raw_obj;
|
||||
const Object* obj;
|
||||
};
|
||||
#if defined(SNAPSHOT_BACKTRACE)
|
||||
union {
|
||||
ObjectPtr raw_parent;
|
||||
const Object* parent;
|
||||
};
|
||||
#endif
|
||||
uint8_t flags;
|
||||
|
||||
bool is_object() const { return IsObjectField::decode(flags); }
|
||||
bool is_original_object() const {
|
||||
return IsOriginalObjectField::decode(flags);
|
||||
}
|
||||
|
||||
void set_is_object(bool value) {
|
||||
flags = IsObjectField::update(value, flags);
|
||||
}
|
||||
|
||||
using IsObjectField = BitField<uint8_t, bool, 0, 1>;
|
||||
using IsOriginalObjectField =
|
||||
BitField<uint8_t, bool, IsObjectField::kNextBit, 1>;
|
||||
bool is_object;
|
||||
};
|
||||
|
||||
// Methods abstracting out the particulars of the underlying concrete writer.
|
||||
|
@ -459,10 +415,6 @@ class ImageWriter : public ValueObject {
|
|||
virtual void AddCodeSymbol(const Code& code,
|
||||
const char* symbol,
|
||||
intptr_t section_offset) = 0;
|
||||
// Creates a static symbol for a read-only data object when appropriate.
|
||||
virtual void AddDataSymbol(const char* symbol,
|
||||
intptr_t section_offset,
|
||||
size_t size) = 0;
|
||||
|
||||
// Overloaded convenience versions of the above virtual methods.
|
||||
|
||||
|
@ -490,47 +442,6 @@ class ImageWriter : public ValueObject {
|
|||
GrowableArray<ObjectData> objects_;
|
||||
GrowableArray<InstructionsData> instructions_;
|
||||
|
||||
#if defined(DART_PRECOMPILER)
|
||||
class SnapshotTextObjectNamer : ValueObject {
|
||||
public:
|
||||
explicit SnapshotTextObjectNamer(Zone* zone)
|
||||
: zone_(ASSERT_NOTNULL(zone)),
|
||||
owner_(Object::Handle(zone)),
|
||||
string_(String::Handle(zone)),
|
||||
insns_(Instructions::Handle(zone)),
|
||||
store_(IsolateGroup::Current()->object_store()) {}
|
||||
|
||||
const char* StubNameForType(const AbstractType& type) const;
|
||||
|
||||
// Returns a unique assembly-safe name for text data to use in symbols.
|
||||
// Assumes that code in the InstructionsData has been allocated a handle.
|
||||
const char* SnapshotNameFor(const InstructionsData& data);
|
||||
// Returns a unique assembly-safe name for read-only data to use in symbols.
|
||||
// Assumes that the ObjectData has already been converted to object handles.
|
||||
const char* SnapshotNameFor(const ObjectData& data);
|
||||
|
||||
private:
|
||||
// Returns a unique assembly-safe name for the given code or read-only
|
||||
// data object for use in symbols.
|
||||
const char* SnapshotNameFor(const Object& object);
|
||||
// Adds a non-unique assembly-safe name for the given object to the given
|
||||
// buffer.
|
||||
void AddNonUniqueNameFor(BaseTextBuffer* buffer, const Object& object);
|
||||
|
||||
Zone* const zone_;
|
||||
Object& owner_;
|
||||
String& string_;
|
||||
Instructions& insns_;
|
||||
ObjectStore* const store_;
|
||||
TypeTestingStubNamer namer_;
|
||||
intptr_t nonce_ = 0;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SnapshotTextObjectNamer);
|
||||
};
|
||||
|
||||
SnapshotTextObjectNamer namer_;
|
||||
#endif
|
||||
|
||||
IdSpace offset_space_ = IdSpace::kSnapshot;
|
||||
V8SnapshotProfileWriter* profile_writer_ = nullptr;
|
||||
const char* const image_type_;
|
||||
|
@ -538,8 +449,12 @@ class ImageWriter : public ValueObject {
|
|||
const char* const instructions_type_;
|
||||
const char* const trampoline_type_;
|
||||
|
||||
// Used to make sure Code symbols are unique across text sections.
|
||||
intptr_t unique_symbol_counter_ = 0;
|
||||
|
||||
template <class T>
|
||||
friend class TraceImageObjectScope;
|
||||
friend class SnapshotTextObjectNamer; // For InstructionsData.
|
||||
|
||||
private:
|
||||
static intptr_t SizeInSnapshotForBytes(intptr_t length);
|
||||
|
@ -588,6 +503,32 @@ class TraceImageObjectScope : ValueObject {
|
|||
DISALLOW_COPY_AND_ASSIGN(TraceImageObjectScope);
|
||||
};
|
||||
|
||||
class SnapshotTextObjectNamer : ValueObject {
|
||||
public:
|
||||
explicit SnapshotTextObjectNamer(Zone* zone)
|
||||
: zone_(ASSERT_NOTNULL(zone)),
|
||||
owner_(Object::Handle(zone)),
|
||||
string_(String::Handle(zone)),
|
||||
insns_(Instructions::Handle(zone)),
|
||||
store_(IsolateGroup::Current()->object_store()) {}
|
||||
|
||||
const char* StubNameForType(const AbstractType& type) const;
|
||||
|
||||
const char* SnapshotNameFor(intptr_t code_index, const Code& code);
|
||||
const char* SnapshotNameFor(intptr_t index,
|
||||
const ImageWriter::InstructionsData& data);
|
||||
|
||||
private:
|
||||
Zone* const zone_;
|
||||
Object& owner_;
|
||||
String& string_;
|
||||
Instructions& insns_;
|
||||
ObjectStore* const store_;
|
||||
TypeTestingStubNamer namer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SnapshotTextObjectNamer);
|
||||
};
|
||||
|
||||
class AssemblyImageWriter : public ImageWriter {
|
||||
public:
|
||||
AssemblyImageWriter(Thread* thread,
|
||||
|
@ -622,7 +563,6 @@ class AssemblyImageWriter : public ImageWriter {
|
|||
virtual void AddCodeSymbol(const Code& code,
|
||||
const char* symbol,
|
||||
intptr_t offset);
|
||||
virtual void AddDataSymbol(const char* symbol, intptr_t offset, size_t size);
|
||||
|
||||
BaseWriteStream* const assembly_stream_;
|
||||
Dwarf* const assembly_dwarf_;
|
||||
|
@ -631,8 +571,8 @@ class AssemblyImageWriter : public ImageWriter {
|
|||
// Used in Relocation to output "(.)" for relocations involving the current
|
||||
// section position and creating local symbols in AddCodeSymbol.
|
||||
const char* current_section_symbol_ = nullptr;
|
||||
// Used for creating local symbols for code and data objects in the
|
||||
// debugging info, if separately written.
|
||||
// Used for creating local symbols for code objects in the debugging info,
|
||||
// if separately written.
|
||||
ZoneGrowableArray<Elf::SymbolData>* current_symbols_ = nullptr;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AssemblyImageWriter);
|
||||
|
@ -676,7 +616,6 @@ class BlobImageWriter : public ImageWriter {
|
|||
virtual void AddCodeSymbol(const Code& code,
|
||||
const char* symbol,
|
||||
intptr_t offset);
|
||||
virtual void AddDataSymbol(const char* symbol, intptr_t offset, size_t size);
|
||||
|
||||
// Set on section entrance to a new array containing the relocations for the
|
||||
// current section.
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "vm/stub_code.h"
|
||||
#include "vm/timeline.h"
|
||||
#include "vm/type_testing_stubs.h"
|
||||
#include "vm/zone_text_buffer.h"
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#include "vm/compiler/backend/flow_graph_compiler.h"
|
||||
|
@ -33,60 +32,57 @@ TypeTestingStubNamer::TypeTestingStubNamer()
|
|||
|
||||
const char* TypeTestingStubNamer::StubNameForType(
|
||||
const AbstractType& type) const {
|
||||
ZoneTextBuffer buffer(Thread::Current()->zone());
|
||||
WriteStubNameForTypeTo(&buffer, type);
|
||||
return buffer.buffer();
|
||||
Zone* Z = Thread::Current()->zone();
|
||||
return OS::SCreate(Z, "TypeTestingStub_%s", StringifyType(type));
|
||||
}
|
||||
|
||||
void TypeTestingStubNamer::WriteStubNameForTypeTo(
|
||||
BaseTextBuffer* buffer,
|
||||
const AbstractType& type) const {
|
||||
buffer->AddString("TypeTestingStub_");
|
||||
StringifyTypeTo(buffer, type);
|
||||
}
|
||||
|
||||
void TypeTestingStubNamer::StringifyTypeTo(BaseTextBuffer* buffer,
|
||||
const char* TypeTestingStubNamer::StringifyType(
|
||||
const AbstractType& type) const {
|
||||
NoSafepointScope no_safepoint;
|
||||
Zone* Z = Thread::Current()->zone();
|
||||
if (type.IsType()) {
|
||||
const intptr_t cid = Type::Cast(type).type_class_id();
|
||||
ClassTable* class_table = IsolateGroup::Current()->class_table();
|
||||
klass_ = class_table->At(cid);
|
||||
ASSERT(!klass_.IsNull());
|
||||
|
||||
const char* curl = "";
|
||||
lib_ = klass_.library();
|
||||
if (!lib_.IsNull()) {
|
||||
string_ = lib_.url();
|
||||
buffer->AddString(string_.ToCString());
|
||||
curl = OS::SCreate(Z, "%s_", string_.ToCString());
|
||||
} else {
|
||||
buffer->Printf("nolib%" Pd "_", nonce_++);
|
||||
static std::atomic<intptr_t> counter = 0;
|
||||
curl = OS::SCreate(Z, "nolib%" Pd "_", counter++);
|
||||
}
|
||||
|
||||
buffer->AddString("_");
|
||||
buffer->AddString(klass_.ScrubbedNameCString());
|
||||
const char* concatenated = AssemblerSafeName(
|
||||
OS::SCreate(Z, "%s_%s", curl, klass_.ScrubbedNameCString()));
|
||||
|
||||
const intptr_t type_parameters = klass_.NumTypeParameters();
|
||||
auto& type_arguments = TypeArguments::Handle(type.arguments());
|
||||
if (!type_arguments.IsNull() && type_parameters > 0) {
|
||||
auto& type_arguments = TypeArguments::Handle();
|
||||
if (type.arguments() != TypeArguments::null() && type_parameters > 0) {
|
||||
type_arguments = type.arguments();
|
||||
ASSERT(type_arguments.Length() >= type_parameters);
|
||||
const intptr_t length = type_arguments.Length();
|
||||
for (intptr_t i = 0; i < type_parameters; ++i) {
|
||||
type_ = type_arguments.TypeAt(length - type_parameters + i);
|
||||
buffer->AddString("__");
|
||||
StringifyTypeTo(buffer, type_);
|
||||
concatenated =
|
||||
OS::SCreate(Z, "%s__%s", concatenated, StringifyType(type_));
|
||||
}
|
||||
}
|
||||
} else if (type.IsTypeParameter()) {
|
||||
buffer->AddString(TypeParameter::Cast(type).CanonicalNameCString());
|
||||
} else {
|
||||
buffer->AddString(type.ToCString());
|
||||
}
|
||||
MakeNameAssemblerSafe(buffer);
|
||||
}
|
||||
|
||||
void TypeTestingStubNamer::MakeNameAssemblerSafe(BaseTextBuffer* buffer) {
|
||||
char* cursor = buffer->buffer();
|
||||
return concatenated;
|
||||
} else if (type.IsTypeParameter()) {
|
||||
return AssemblerSafeName(
|
||||
OS::SCreate(Z, "%s", TypeParameter::Cast(type).CanonicalNameCString()));
|
||||
} else {
|
||||
return AssemblerSafeName(OS::SCreate(Z, "%s", type.ToCString()));
|
||||
}
|
||||
}
|
||||
|
||||
const char* TypeTestingStubNamer::AssemblerSafeName(char* cname) {
|
||||
char* cursor = cname;
|
||||
while (*cursor != '\0') {
|
||||
char c = *cursor;
|
||||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
||||
|
@ -95,6 +91,7 @@ void TypeTestingStubNamer::MakeNameAssemblerSafe(BaseTextBuffer* buffer) {
|
|||
}
|
||||
cursor++;
|
||||
}
|
||||
return cname;
|
||||
}
|
||||
|
||||
CodePtr TypeTestingStubGenerator::DefaultCodeForType(
|
||||
|
|
|
@ -24,19 +24,15 @@ class TypeTestingStubNamer {
|
|||
//
|
||||
// (only during dart_boostrap).
|
||||
const char* StubNameForType(const AbstractType& type) const;
|
||||
void WriteStubNameForTypeTo(BaseTextBuffer* buffer,
|
||||
const AbstractType& type) const;
|
||||
|
||||
private:
|
||||
void StringifyTypeTo(BaseTextBuffer* buffer, const AbstractType& type) const;
|
||||
// Converts the contents of the buffer to an assembly-safe name.
|
||||
static void MakeNameAssemblerSafe(BaseTextBuffer* buffer);
|
||||
const char* StringifyType(const AbstractType& type) const;
|
||||
static const char* AssemblerSafeName(char* cname);
|
||||
|
||||
Library& lib_;
|
||||
Class& klass_;
|
||||
AbstractType& type_;
|
||||
String& string_;
|
||||
mutable intptr_t nonce_ = 0;
|
||||
};
|
||||
|
||||
class TypeTestingStubGenerator {
|
||||
|
|
Loading…
Reference in a new issue