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
|
## 0.5.0
|
||||||
|
|
||||||
- Require Dart >= 2.17 (enhanced enum support)
|
- Require Dart >= 2.17 (enhanced enum support)
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue