[vm/aot] Remove object wrapping of bare instructions for AOT snapshots.

Now, when writing an AOT snapshot in bare instructions mode, only
the actual instructions in the RawInstructions payload are serialized
instead of the entire RawInstructions object.

Since there are no longer RawInstructions objects in these AOT
snapshots, we also change how Code objects are serialized. Instead
of just containing a reference to the RawInstructions object, we
serialize two pieces of information: where the instructions
payload for this Code object begins and whether there was a single
entry for the instructions payload. (To save space, the single
entry bit is serialized as the low order bit of the unchecked
offset, which was already being serialized).

While we also need the length of the instructions payload, we
approximate it for all but the last Code object by subtracting
the next Code object's payload start from this Code object's
payload start. For the last Code object, we assume it extends
to the end of the instructions image.

Changes on flutter gallery in release mode:
armv7: instructions size -2.66%, total size -1.68%
armv8: instructions size -5.81%, total size -3.49%

Fixes https://github.com/dart-lang/sdk/issues/38451.

Change-Id: Ia458e8d99bae18f5c3b6e849df2519027f06f574
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm_x64-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-precomp-mac-release-simarm64-try,vm-kernel-precomp-win-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/131067
Commit-Queue: Teagan Strickland <sstrickl@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Teagan Strickland 2020-02-04 10:28:43 +00:00 committed by commit-bot@chromium.org
parent 56ca547c8c
commit 7475c637c3
29 changed files with 748 additions and 204 deletions

View file

@ -11,7 +11,12 @@ import "package:vm/v8_snapshot_profile.dart";
import 'use_flag_test_helper.dart';
test({String dillPath, bool useAsm, bool stripFlag, bool stripUtil}) async {
test(
{String dillPath,
bool useAsm,
bool useBare,
bool stripFlag,
bool stripUtil}) async {
// The assembler may add extra unnecessary information to the compiled
// snapshot whether or not we generate DWARF information in the assembly, so
// we force the use of a utility when generating assembly.
@ -23,6 +28,7 @@ test({String dillPath, bool useAsm, bool stripFlag, bool stripUtil}) async {
final tempDirPrefix = 'v8-snapshot-profile' +
(useAsm ? '-assembly' : '-elf') +
(useBare ? '-bare' : '-nonbare') +
(stripFlag ? '-intstrip' : '') +
(stripUtil ? '-extstrip' : '');
@ -32,6 +38,7 @@ test({String dillPath, bool useAsm, bool stripFlag, bool stripUtil}) async {
final snapshotPath = path.join(tempDir, 'test.snap');
final commonSnapshotArgs = [
if (stripFlag) '--strip',
useBare ? '--use-bare-instructions' : '--no-use-bare-instructions',
"--write-v8-snapshot-profile-to=$profilePath",
dillPath,
];
@ -71,7 +78,7 @@ test({String dillPath, bool useAsm, bool stripFlag, bool stripUtil}) async {
// graph (in some cases the shallow size can legitimately be 0, e.g. for
// "base objects").
for (final int node in profile.nodes) {
Expect.notEquals(profile[node].type, "Unknown",
Expect.notEquals("Unknown", profile[node].type,
"unknown node at ID ${profile[node].id}");
}
@ -89,6 +96,7 @@ test({String dillPath, bool useAsm, bool stripFlag, bool stripUtil}) async {
final actual = await File(strippedPath).length();
final expected = profile.accountedBytes;
final bareUsed = useBare ? "bare" : "non-bare";
final fileType = useAsm ? "assembly" : "ELF";
String stripPrefix = "";
if (stripFlag && stripUtil) {
@ -100,7 +108,7 @@ test({String dillPath, bool useAsm, bool stripFlag, bool stripUtil}) async {
}
Expect.approxEquals(expected, actual, 0.03 * actual,
"failed on $stripPrefix$fileType snapshot type.");
"failed on $bareUsed $stripPrefix$fileType snapshot type.");
});
}
@ -214,7 +222,17 @@ main() async {
// Test stripped ELF generation directly.
await test(
dillPath: dillPath, stripFlag: true, stripUtil: false, useAsm: false);
dillPath: dillPath,
stripFlag: true,
stripUtil: false,
useAsm: false,
useBare: false);
await test(
dillPath: dillPath,
stripFlag: true,
stripUtil: false,
useAsm: false,
useBare: true);
// We neither generate assembly nor have a stripping utility on Windows.
if (Platform.isWindows) {
@ -228,7 +246,17 @@ main() async {
} else {
// Test unstripped ELF generation that is then stripped externally.
await test(
dillPath: dillPath, stripFlag: false, stripUtil: true, useAsm: false);
dillPath: dillPath,
stripFlag: false,
stripUtil: true,
useAsm: false,
useBare: false);
await test(
dillPath: dillPath,
stripFlag: false,
stripUtil: true,
useAsm: false,
useBare: true);
}
// TODO(sstrickl): Currently we can't assemble for SIMARM64 on MacOSX.
@ -241,9 +269,29 @@ main() async {
// Test stripped assembly generation that is then compiled and stripped.
await test(
dillPath: dillPath, stripFlag: true, stripUtil: true, useAsm: true);
dillPath: dillPath,
stripFlag: true,
stripUtil: true,
useAsm: true,
useBare: false);
await test(
dillPath: dillPath,
stripFlag: true,
stripUtil: true,
useAsm: true,
useBare: true);
// Test unstripped assembly generation that is then compiled and stripped.
await test(
dillPath: dillPath, stripFlag: false, stripUtil: true, useAsm: true);
dillPath: dillPath,
stripFlag: false,
stripUtil: true,
useAsm: true,
useBare: false);
await test(
dillPath: dillPath,
stripFlag: false,
stripUtil: true,
useAsm: true,
useBare: true);
});
}

View file

@ -28,6 +28,7 @@ namespace dart {
V(Code) \
V(Bytecode) \
V(Instructions) \
V(InstructionsSection) \
V(ObjectPool) \
V(PcDescriptors) \
V(CodeSourceMap) \

View file

@ -1509,15 +1509,16 @@ class CodeSerializationCluster : public SerializationCluster {
s->UnexpectedObject(code, "Disabled code");
}
s->WriteInstructions(code->ptr()->instructions_, code);
s->WriteUnsigned(code->ptr()->unchecked_offset_);
s->WriteInstructions(code->ptr()->instructions_,
code->ptr()->unchecked_offset_, code);
if (kind == Snapshot::kFullJIT) {
// TODO(rmacnak): Fix references to disabled code before serializing.
// For now, we may write the FixCallersTarget or equivalent stub. This
// will cause a fixup if this code is called.
s->WriteInstructions(code->ptr()->active_instructions_, code);
s->WriteUnsigned(code->ptr()->unchecked_entry_point_ -
code->ptr()->entry_point_);
const uint32_t active_unchecked_offset =
code->ptr()->unchecked_entry_point_ - code->ptr()->entry_point_;
s->WriteInstructions(code->ptr()->active_instructions_,
active_unchecked_offset, code);
}
WriteField(code, object_pool_);
@ -1598,24 +1599,10 @@ class CodeDeserializationCluster : public DeserializationCluster {
void ReadFill(Deserializer* d) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawCode* code = reinterpret_cast<RawCode*>(d->Ref(id));
auto const code = reinterpret_cast<RawCode*>(d->Ref(id));
Deserializer::InitializeHeader(code, kCodeCid, Code::InstanceSize(0));
RawInstructions* instr = d->ReadInstructions();
uint32_t unchecked_offset = d->ReadUnsigned();
code->ptr()->instructions_ = instr;
#if !defined(DART_PRECOMPILED_RUNTIME)
code->ptr()->unchecked_offset_ = unchecked_offset;
if (d->kind() == Snapshot::kFullJIT) {
instr = d->ReadInstructions();
unchecked_offset = d->ReadUnsigned();
}
code->ptr()->active_instructions_ = instr;
#endif // !DART_PRECOMPILED_RUNTIME
Code::InitializeCachedEntryPointsFrom(code, instr, unchecked_offset);
d->ReadInstructions(code);
code->ptr()->object_pool_ =
reinterpret_cast<RawObjectPool*>(d->ReadRef());
@ -1651,7 +1638,32 @@ class CodeDeserializationCluster : public DeserializationCluster {
#endif
code->ptr()->state_bits_ = d->Read<int32_t>();
#if defined(DART_PRECOMPILED_RUNTIME)
if (FLAG_use_bare_instructions && id != start_index_) {
// The following assumes that ReadInstructions put the offset of the
// entry point from the payload start into instructions_length_. We
// use this to calculate the length of the previous payload.
RawCode* prev = reinterpret_cast<RawCode*>(d->Ref(id - 1));
const uword prev_payload_start =
prev->ptr()->entry_point_ - prev->ptr()->instructions_length_;
const uword curr_payload_start =
code->ptr()->entry_point_ - code->ptr()->instructions_length_;
prev->ptr()->instructions_length_ =
curr_payload_start - prev_payload_start;
}
#endif
}
#if defined(DART_PRECOMPILED_RUNTIME)
if (FLAG_use_bare_instructions) {
// Since there is no following Code object, we assume that the last Code
// object ends at the end of the instructions snapshot.
auto const code = reinterpret_cast<RawCode*>(d->Ref(stop_index_ - 1));
const uword curr_payload_start =
code->ptr()->entry_point_ - code->ptr()->instructions_length_;
code->ptr()->instructions_length_ =
d->GetBareInstructionsEnd() - curr_payload_start;
}
#endif
}
#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
@ -4675,7 +4687,9 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
}
#if !defined(DART_PRECOMPILED_RUNTIME)
void Serializer::WriteInstructions(RawInstructions* instr, RawCode* code) {
void Serializer::WriteInstructions(RawInstructions* instr,
uint32_t unchecked_offset,
RawCode* code) {
ASSERT(code != Code::null());
const intptr_t offset = image_writer_->GetTextOffsetFor(instr, code);
@ -4684,6 +4698,17 @@ void Serializer::WriteInstructions(RawInstructions* instr, RawCode* code) {
UnexpectedObject(code, "Expected instructions to reuse");
}
Write<uint32_t>(offset);
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
// When writing only instruction payloads, we also need to serialize
// whether there was a single entry. We add this as the low order bit
// in the unchecked_offset.
ASSERT(unchecked_offset <= kMaxInt32);
const uint32_t payload_info =
(unchecked_offset << 1) | (Code::HasMonomorphicEntry(code) ? 0x1 : 0x0);
WriteUnsigned(payload_info);
} else {
WriteUnsigned(unchecked_offset);
}
// If offset < 0, it's pointing to a shared instruction. We don't profile
// references to shared text/data (since they don't consume any space). Of
@ -5423,11 +5448,74 @@ RawApiError* FullSnapshotReader::ConvertToApiError(char* message) {
return ApiError::New(msg, Heap::kOld);
}
RawInstructions* Deserializer::ReadInstructions() {
uint32_t offset = Read<uint32_t>();
return image_reader_->GetInstructionsAt(offset);
void Deserializer::ReadInstructions(RawCode* code) {
#if defined(DART_PRECOMPILED_RUNTIME)
if (FLAG_use_bare_instructions) {
const uint32_t bare_offset = Read<uint32_t>();
const uword payload_start =
image_reader_->GetBareInstructionsAt(bare_offset);
const uint32_t payload_info = ReadUnsigned();
const uint32_t unchecked_offset = payload_info >> 1;
const bool has_monomorphic_entrypoint = (payload_info & 0x1) == 0x1;
const uword entry_offset = has_monomorphic_entrypoint
? Instructions::kPolymorphicEntryOffsetAOT
: 0;
const uword monomorphic_entry_offset =
has_monomorphic_entrypoint ? Instructions::kMonomorphicEntryOffsetAOT
: 0;
const uword entry_point = payload_start + entry_offset;
const uword monomorphic_entry_point =
payload_start + monomorphic_entry_offset;
code->ptr()->instructions_ = Instructions::null();
code->ptr()->entry_point_ = entry_point;
code->ptr()->unchecked_entry_point_ = entry_point + unchecked_offset;
code->ptr()->monomorphic_entry_point_ = monomorphic_entry_point;
code->ptr()->monomorphic_unchecked_entry_point_ =
monomorphic_entry_point + unchecked_offset;
// We don't serialize the length of the instructions payload. Instead, the
// deserializer calculates an approximate length (may include padding)
// by subtracting the payload offset of the next Code object (if any)
// from this one. (For the last Code object, we assume its serialization
// extends to the end of the instructions image.)
//
// Since the Code object doesn't include a field for the payload start,
// we store the entry_offset (calculated above) in instructions_length_
// for now, and subtract it from entry_point_ later after reading the
// next Code object.
ASSERT(entry_offset <= kMaxUint32);
code->ptr()->instructions_length_ = entry_offset;
return;
}
#endif
const uint32_t offset = Read<uint32_t>();
RawInstructions* instr = image_reader_->GetInstructionsAt(offset);
uint32_t unchecked_offset = ReadUnsigned();
code->ptr()->instructions_ = instr;
#if defined(DART_PRECOMPILED_RUNTIME)
code->ptr()->instructions_length_ = Instructions::Size(instr);
#else
code->ptr()->unchecked_offset_ = unchecked_offset;
if (kind() == Snapshot::kFullJIT) {
const uint32_t active_offset = Read<uint32_t>();
instr = image_reader_->GetInstructionsAt(active_offset);
unchecked_offset = ReadUnsigned();
}
code->ptr()->active_instructions_ = instr;
#endif
Code::InitializeCachedEntryPointsFrom(code, instr, unchecked_offset);
}
#if defined(DART_PRECOMPILED_RUNTIME)
uword Deserializer::GetBareInstructionsEnd() {
return image_reader_->GetBareInstructionsEnd();
}
#endif
RawObject* Deserializer::GetObjectAt(uint32_t offset) const {
return image_reader_->GetObjectAt(offset);
}

View file

@ -358,7 +358,9 @@ class Serializer : public ThreadStackResource {
Write<int32_t>(cid);
}
void WriteInstructions(RawInstructions* instr, RawCode* code);
void WriteInstructions(RawInstructions* instr,
uint32_t unchecked_offset,
RawCode* code);
uint32_t GetDataOffset(RawObject* object) const;
void TraceDataOffset(uint32_t offset);
intptr_t GetDataSize() const;
@ -559,7 +561,8 @@ class Deserializer : public ThreadStackResource {
return Read<int32_t>();
}
RawInstructions* ReadInstructions();
ONLY_IN_PRECOMPILED(uword GetBareInstructionsEnd());
void ReadInstructions(RawCode* code);
RawObject* GetObjectAt(uint32_t offset) const;
void SkipHeader() { stream_.SetPosition(Snapshot::kHeaderSize); }

View file

@ -303,7 +303,7 @@ class AssemblerBase : public StackResource {
explicit AssemblerBase(ObjectPoolBuilder* object_pool_builder)
: StackResource(ThreadState::Current()),
prologue_offset_(-1),
has_single_entry_point_(true),
has_monomorphic_entry_(false),
object_pool_builder_(object_pool_builder) {}
virtual ~AssemblerBase();
@ -315,7 +315,7 @@ class AssemblerBase : public StackResource {
ObjectPoolBuilder& object_pool_builder() { return *object_pool_builder_; }
intptr_t prologue_offset() const { return prologue_offset_; }
bool has_single_entry_point() const { return has_single_entry_point_; }
bool has_monomorphic_entry() const { return has_monomorphic_entry_; }
void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
static bool EmittingComments();
@ -370,7 +370,7 @@ class AssemblerBase : public StackResource {
protected:
AssemblerBuffer buffer_; // Contains position independent code.
int32_t prologue_offset_;
bool has_single_entry_point_;
bool has_monomorphic_entry_;
intptr_t unchecked_entry_offset_ = 0;

View file

@ -3437,7 +3437,7 @@ void Assembler::LeaveStubFrame() {
// R0 receiver, R9 ICData entries array
// Preserve R4 (ARGS_DESC_REG), not required today, but maybe later.
void Assembler::MonomorphicCheckedEntryJIT() {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
#if defined(TESTING) || defined(DEBUG)
bool saved_use_far_branches = use_far_branches();
set_use_far_branches(false);
@ -3473,7 +3473,7 @@ void Assembler::MonomorphicCheckedEntryJIT() {
// R0 receiver, R9 guarded cid as Smi.
// Preserve R4 (ARGS_DESC_REG), not required today, but maybe later.
void Assembler::MonomorphicCheckedEntryAOT() {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
#if defined(TESTING) || defined(DEBUG)
bool saved_use_far_branches = use_far_branches();
set_use_far_branches(false);
@ -3498,7 +3498,7 @@ void Assembler::MonomorphicCheckedEntryAOT() {
}
void Assembler::BranchOnMonomorphicCheckedEntryJIT(Label* label) {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
while (CodeSize() < target::Instructions::kMonomorphicEntryOffsetJIT) {
bkpt(0);
}

View file

@ -1532,7 +1532,7 @@ void Assembler::LeaveStubFrame() {
// R0 receiver, R5 ICData entries array
// Preserve R4 (ARGS_DESC_REG), not required today, but maybe later.
void Assembler::MonomorphicCheckedEntryJIT() {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
const bool saved_use_far_branches = use_far_branches();
set_use_far_branches(false);
const intptr_t start = CodeSize();
@ -1569,7 +1569,7 @@ void Assembler::MonomorphicCheckedEntryJIT() {
// R0 receiver, R5 guarded cid as Smi.
// Preserve R4 (ARGS_DESC_REG), not required today, but maybe later.
void Assembler::MonomorphicCheckedEntryAOT() {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
bool saved_use_far_branches = use_far_branches();
set_use_far_branches(false);
@ -1595,7 +1595,7 @@ void Assembler::MonomorphicCheckedEntryAOT() {
}
void Assembler::BranchOnMonomorphicCheckedEntryJIT(Label* label) {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
while (CodeSize() < target::Instructions::kMonomorphicEntryOffsetJIT) {
brk(0);
}

View file

@ -2117,7 +2117,7 @@ void Assembler::EmitEntryFrameVerification() {
// EBX receiver, ECX ICData entries array
// Preserve EDX (ARGS_DESC_REG), not required today, but maybe later.
void Assembler::MonomorphicCheckedEntryJIT() {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
intptr_t start = CodeSize();
Label have_cid, miss;
Bind(&miss);
@ -2156,7 +2156,7 @@ void Assembler::MonomorphicCheckedEntryAOT() {
}
void Assembler::BranchOnMonomorphicCheckedEntryJIT(Label* label) {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
while (CodeSize() < target::Instructions::kMonomorphicEntryOffsetJIT) {
int3();
}

View file

@ -1798,7 +1798,7 @@ void Assembler::LeaveStubFrame() {
// RDX receiver, RBX ICData entries array
// Preserve R10 (ARGS_DESC_REG), not required today, but maybe later.
void Assembler::MonomorphicCheckedEntryJIT() {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
intptr_t start = CodeSize();
Label have_cid, miss;
Bind(&miss);
@ -1831,7 +1831,7 @@ void Assembler::MonomorphicCheckedEntryJIT() {
}
void Assembler::MonomorphicCheckedEntryAOT() {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
intptr_t start = CodeSize();
Label have_cid, miss;
Bind(&miss);
@ -1862,7 +1862,7 @@ void Assembler::MonomorphicCheckedEntryAOT() {
}
void Assembler::BranchOnMonomorphicCheckedEntryJIT(Label* label) {
has_single_entry_point_ = false;
has_monomorphic_entry_ = true;
while (CodeSize() < target::Instructions::kMonomorphicEntryOffsetJIT) {
int3();
}

View file

@ -258,8 +258,7 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname,
PcDescriptors::Handle(zone, code.pc_descriptors());
THR_Print("%s}\n", descriptors.ToCString());
const auto& instructions = Instructions::Handle(code.instructions());
const uword start = instructions.PayloadStart();
const uword start = code.PayloadStart();
const uword base = FLAG_disassemble_relative ? 0 : start;
#if !defined(DART_PRECOMPILED_RUNTIME)

View file

@ -157,8 +157,7 @@ void CodeRelocator::FindInstructionAndCallLimits() {
offset_into_target = call.distance();
}
const uword destination_payload =
Instructions::PayloadStart(destination_.instructions());
const uword destination_payload = destination_.PayloadStart();
const uword entry_point = call_entry_point == Code::kUncheckedEntry
? destination_.UncheckedEntryPoint()
: destination_.EntryPoint();
@ -272,17 +271,16 @@ void CodeRelocator::ScanCallTargets(const Code& code,
offset_into_target = call.distance();
}
const uword destination_payload =
Instructions::PayloadStart(destination_.instructions());
const uword destination_payload = destination_.PayloadStart();
const uword entry_point = call_entry_point == Code::kUncheckedEntry
? destination_.UncheckedEntryPoint()
: destination_.EntryPoint();
offset_into_target += (entry_point - destination_payload);
const intptr_t text_offset = code_text_offset +
compiler::target::Instructions::HeaderSize() +
call_instruction_offset;
const intptr_t text_offset =
code_text_offset + AdjustPayloadOffset(call_instruction_offset);
UnresolvedCall unresolved_call(code.raw(), call_instruction_offset,
text_offset, destination_.raw(),
offset_into_target);
@ -368,12 +366,12 @@ void CodeRelocator::ResolveCallToDestination(UnresolvedCall* unresolved_call,
const intptr_t call_text_offset = unresolved_call->text_offset;
const intptr_t call_offset = unresolved_call->call_offset;
auto caller = Code::InstructionsOf(unresolved_call->caller);
const int32_t distance = destination_text - call_text_offset;
{
uword addr = Instructions::PayloadStart(caller) + call_offset;
auto const caller = unresolved_call->caller;
uword addr = Code::PayloadStartOf(caller) + call_offset;
if (FLAG_write_protect_code) {
addr -= HeapPage::Of(caller)->AliasOffset();
addr -= HeapPage::Of(Code::InstructionsOf(caller))->AliasOffset();
}
PcRelativeCallPattern call(addr);
ASSERT(call.IsValid());
@ -510,9 +508,15 @@ void CodeRelocator::BuildTrampolinesForAlmostOutOfRangeCalls() {
intptr_t CodeRelocator::FindDestinationInText(
const RawInstructions* destination,
intptr_t offset_into_target) {
auto destination_offset = text_offsets_.LookupValue(destination);
return destination_offset + compiler::target::Instructions::HeaderSize() +
offset_into_target;
auto const destination_offset = text_offsets_.LookupValue(destination);
return destination_offset + AdjustPayloadOffset(offset_into_target);
}
intptr_t CodeRelocator::AdjustPayloadOffset(intptr_t payload_offset) {
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
return payload_offset;
}
return compiler::target::Instructions::HeaderSize() + payload_offset;
}
#endif // defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)

View file

@ -178,6 +178,8 @@ class CodeRelocator : public StackResource {
intptr_t FindDestinationInText(const RawInstructions* destination,
intptr_t offset_into_target);
static intptr_t AdjustPayloadOffset(intptr_t payload_offset);
bool IsTargetInRangeFor(UnresolvedCall* unresolved_call,
intptr_t target_text_offset);

View file

@ -513,6 +513,11 @@ const word StoreBufferBlock::kSize = dart::StoreBufferBlock::kSize;
const word MarkingStackBlock::kSize = dart::MarkingStackBlock::kSize;
word InstructionsSection::HeaderSize() {
return Utils::RoundUp(InstructionsSection::UnalignedHeaderSize(),
target::kWordSize);
}
word Instructions::HeaderSize() {
return Utils::RoundUp(Instructions::UnalignedHeaderSize(), target::kWordSize);
}
@ -911,6 +916,10 @@ word MonomorphicSmiableCall::NextFieldOffset() {
return -kWordSize;
}
word InstructionsSection::NextFieldOffset() {
return -kWordSize;
}
word Instructions::NextFieldOffset() {
return -kWordSize;
}

View file

@ -1063,6 +1063,14 @@ class ClassTable : public AllStatic {
static const word kSizeOfClassPairLog2;
};
class InstructionsSection : public AllStatic {
public:
static word HeaderSize();
static word UnalignedHeaderSize();
static word InstanceSize();
static word NextFieldOffset();
};
class Instructions : public AllStatic {
public:
static const word kMonomorphicEntryOffsetJIT;

View file

@ -415,6 +415,10 @@ static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
8;
static constexpr dart::compiler::target::word InstructionsSection_InstanceSize =
8;
static constexpr dart::compiler::target::word
InstructionsSection_UnalignedHeaderSize = 8;
static constexpr dart::compiler::target::word Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Integer_InstanceSize = 4;
static constexpr dart::compiler::target::word KernelProgramInfo_InstanceSize =
@ -874,6 +878,10 @@ static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
12;
static constexpr dart::compiler::target::word InstructionsSection_InstanceSize =
12;
static constexpr dart::compiler::target::word
InstructionsSection_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Integer_InstanceSize = 8;
static constexpr dart::compiler::target::word KernelProgramInfo_InstanceSize =
@ -1326,6 +1334,10 @@ static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
8;
static constexpr dart::compiler::target::word InstructionsSection_InstanceSize =
8;
static constexpr dart::compiler::target::word
InstructionsSection_UnalignedHeaderSize = 8;
static constexpr dart::compiler::target::word Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Integer_InstanceSize = 4;
static constexpr dart::compiler::target::word KernelProgramInfo_InstanceSize =
@ -1786,6 +1798,10 @@ static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
12;
static constexpr dart::compiler::target::word InstructionsSection_InstanceSize =
12;
static constexpr dart::compiler::target::word
InstructionsSection_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Integer_InstanceSize = 8;
static constexpr dart::compiler::target::word KernelProgramInfo_InstanceSize =
@ -2238,6 +2254,10 @@ static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
8;
static constexpr dart::compiler::target::word InstructionsSection_InstanceSize =
8;
static constexpr dart::compiler::target::word
InstructionsSection_UnalignedHeaderSize = 8;
static constexpr dart::compiler::target::word Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Integer_InstanceSize = 4;
static constexpr dart::compiler::target::word KernelProgramInfo_InstanceSize =
@ -2691,6 +2711,10 @@ static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
12;
static constexpr dart::compiler::target::word InstructionsSection_InstanceSize =
12;
static constexpr dart::compiler::target::word
InstructionsSection_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Integer_InstanceSize = 8;
static constexpr dart::compiler::target::word KernelProgramInfo_InstanceSize =
@ -3137,6 +3161,10 @@ static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
8;
static constexpr dart::compiler::target::word InstructionsSection_InstanceSize =
8;
static constexpr dart::compiler::target::word
InstructionsSection_UnalignedHeaderSize = 8;
static constexpr dart::compiler::target::word Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Integer_InstanceSize = 4;
static constexpr dart::compiler::target::word KernelProgramInfo_InstanceSize =
@ -3591,6 +3619,10 @@ static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
12;
static constexpr dart::compiler::target::word InstructionsSection_InstanceSize =
12;
static constexpr dart::compiler::target::word
InstructionsSection_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word Integer_InstanceSize = 8;
static constexpr dart::compiler::target::word KernelProgramInfo_InstanceSize =
@ -4079,6 +4111,10 @@ static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word
AOT_Instructions_UnalignedHeaderSize = 8;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_InstanceSize = 8;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_UnalignedHeaderSize = 8;
static constexpr dart::compiler::target::word AOT_Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Integer_InstanceSize = 4;
static constexpr dart::compiler::target::word
@ -4581,6 +4617,10 @@ static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
static constexpr dart::compiler::target::word
AOT_Instructions_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_InstanceSize = 12;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word AOT_Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Integer_InstanceSize = 8;
static constexpr dart::compiler::target::word
@ -5087,6 +5127,10 @@ static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
static constexpr dart::compiler::target::word
AOT_Instructions_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_InstanceSize = 12;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word AOT_Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Integer_InstanceSize = 8;
static constexpr dart::compiler::target::word
@ -5549,7 +5593,7 @@ static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 112;
static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 28;
static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 20;
static constexpr dart::compiler::target::word AOT_Code_InstanceSize = 60;
static constexpr dart::compiler::target::word AOT_Code_InstanceSize = 64;
static constexpr dart::compiler::target::word AOT_CodeSourceMap_InstanceSize =
8;
static constexpr dart::compiler::target::word
@ -5582,6 +5626,10 @@ static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word
AOT_Instructions_UnalignedHeaderSize = 8;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_InstanceSize = 8;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_UnalignedHeaderSize = 8;
static constexpr dart::compiler::target::word AOT_Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Integer_InstanceSize = 4;
static constexpr dart::compiler::target::word
@ -6077,6 +6125,10 @@ static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
static constexpr dart::compiler::target::word
AOT_Instructions_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_InstanceSize = 12;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word AOT_Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Integer_InstanceSize = 8;
static constexpr dart::compiler::target::word
@ -6576,6 +6628,10 @@ static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
static constexpr dart::compiler::target::word
AOT_Instructions_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_InstanceSize = 12;
static constexpr dart::compiler::target::word
AOT_InstructionsSection_UnalignedHeaderSize = 12;
static constexpr dart::compiler::target::word AOT_Int32x4_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_Integer_InstanceSize = 8;
static constexpr dart::compiler::target::word

View file

@ -286,6 +286,8 @@
SIZEOF(Instance, InstanceSize, RawInstance) \
SIZEOF(Instructions, InstanceSize, RawInstructions) \
SIZEOF(Instructions, UnalignedHeaderSize, RawInstructions) \
SIZEOF(InstructionsSection, InstanceSize, RawInstructionsSection) \
SIZEOF(InstructionsSection, UnalignedHeaderSize, RawInstructionsSection) \
SIZEOF(Int32x4, InstanceSize, RawInt32x4) \
SIZEOF(Integer, InstanceSize, RawInteger) \
SIZEOF(KernelProgramInfo, InstanceSize, RawKernelProgramInfo) \

View file

@ -78,6 +78,12 @@ const intptr_t kDefaultMaxOldGenHeapSize = (kWordSize <= 4) ? 1536 : 30720;
#define NOT_IN_PRECOMPILED(code) code
#endif // defined(DART_PRECOMPILED_RUNTIME)
#if defined(DART_PRECOMPILED_RUNTIME)
#define ONLY_IN_PRECOMPILED(code) code
#else
#define ONLY_IN_PRECOMPILED(code)
#endif // defined(DART_PRECOMPILED_RUNTIME)
#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64) || \
defined(TARGET_ARCH_X64)
#define ONLY_IN_ARM_ARM64_X64(code) code

View file

@ -5,6 +5,7 @@
#include "vm/image_snapshot.h"
#include "platform/assert.h"
#include "vm/class_id.h"
#include "vm/compiler/backend/code_statistics.h"
#include "vm/compiler/runtime_api.h"
#include "vm/dwarf.h"
@ -135,6 +136,25 @@ int32_t ImageWriter::GetTextOffsetFor(RawInstructions* instructions,
return offset;
}
static intptr_t InstructionsSizeInSnapshot(RawInstructions* raw) {
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
// Currently, we align bare instruction payloads on 4 byte boundaries.
//
// If we later decide to align on larger boundaries to put entries at the
// start of cache lines, make sure to account for entry points that are
// _not_ at the start of the payload.
return Utils::RoundUp(Instructions::Size(raw),
ImageWriter::kBareInstructionsAlignment);
}
#if defined(IS_SIMARM_X64)
return Utils::RoundUp(
compiler::target::Instructions::HeaderSize() + Instructions::Size(raw),
compiler::target::ObjectAlignment::kObjectAlignment);
#else
return raw->HeapSize();
#endif
}
#if defined(IS_SIMARM_X64)
static intptr_t CompressedStackMapsSizeInSnapshot(intptr_t payload_size) {
// We do not need to round the non-payload size up to a word boundary because
@ -171,11 +191,6 @@ static intptr_t PcDescriptorsSizeInSnapshot(intptr_t len) {
compiler::target::ObjectAlignment::kObjectAlignment);
}
static intptr_t InstructionsSizeInSnapshot(intptr_t len) {
return Utils::RoundUp(compiler::target::Instructions::HeaderSize() + len,
compiler::target::ObjectAlignment::kObjectAlignment);
}
intptr_t ImageWriter::SizeInSnapshot(RawObject* raw_object) {
const classid_t cid = raw_object->GetClassId();
@ -201,7 +216,7 @@ intptr_t ImageWriter::SizeInSnapshot(RawObject* raw_object) {
}
case kInstructionsCid: {
RawInstructions* raw_insns = static_cast<RawInstructions*>(raw_object);
return InstructionsSizeInSnapshot(Instructions::Size(raw_insns));
return InstructionsSizeInSnapshot(raw_insns);
}
default: {
const Class& clazz = Class::Handle(Object::Handle(raw_object).clazz());
@ -211,8 +226,13 @@ intptr_t ImageWriter::SizeInSnapshot(RawObject* raw_object) {
}
}
#else // defined(IS_SIMARM_X64)
intptr_t ImageWriter::SizeInSnapshot(RawObject* raw_object) {
return raw_object->HeapSize();
intptr_t ImageWriter::SizeInSnapshot(RawObject* raw) {
switch (raw->GetClassId()) {
case kInstructionsCid:
return InstructionsSizeInSnapshot(static_cast<RawInstructions*>(raw));
default:
return raw->HeapSize();
}
}
#endif // defined(IS_SIMARM_X64)
@ -556,6 +576,9 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
#else
Zone* zone = Thread::Current()->zone();
const bool bare_instruction_payloads =
FLAG_precompiled_mode && FLAG_use_bare_instructions;
#if defined(DART_PRECOMPILER)
const char* bss_symbol =
vm ? "_kDartVmSnapshotBss" : "_kDartIsolateSnapshotBss";
@ -572,13 +595,14 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
// Start snapshot at page boundary.
ASSERT(VirtualMemory::PageSize() >= kMaxObjectAlignment);
assembly_stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize());
Align(VirtualMemory::PageSize());
assembly_stream_.Print("%s:\n", instructions_symbol);
// This head also provides the gap to make the instructions snapshot
// look like a HeapPage.
intptr_t instructions_length = next_text_offset_;
WriteWordLiteralText(instructions_length);
const intptr_t image_size = Utils::RoundUp(
next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
WriteWordLiteralText(image_size);
#if defined(DART_PRECOMPILER)
assembly_stream_.Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
@ -592,6 +616,43 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
WriteWordLiteralText(0);
}
if (bare_instruction_payloads) {
const intptr_t image_payload_length = image_size - Image::kHeaderSize;
// Add the RawInstructionsSection header.
uword marked_tags = 0;
marked_tags = RawObject::OldBit::update(true, marked_tags);
marked_tags = RawObject::OldAndNotRememberedBit::update(true, marked_tags);
marked_tags = RawObject::SizeTag::update(image_payload_length, marked_tags);
marked_tags =
RawObject::ClassIdTag::update(kInstructionsSectionCid, marked_tags);
WriteWordLiteralText(marked_tags);
// Calculated using next_text_offset_, which doesn't include post-payload
// padding to object alignment.
const intptr_t instructions_length =
next_text_offset_ - Image::kHeaderSize -
compiler::target::InstructionsSection::HeaderSize();
WriteWordLiteralText(instructions_length);
if (profile_writer_ != nullptr) {
const intptr_t offset = Image::kHeaderSize;
const intptr_t non_instruction_bytes =
compiler::target::InstructionsSection::HeaderSize();
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
"InstructionsSection",
/*name=*/nullptr);
profile_writer_->AttributeBytesTo({offset_space_, offset},
non_instruction_bytes);
profile_writer_->AddRoot({offset_space_, offset});
}
}
const intptr_t section_headers_size =
Image::kHeaderSize +
(bare_instruction_payloads
? compiler::target::InstructionsSection::HeaderSize()
: 0);
FrameUnwindPrologue();
PcDescriptors& descriptors = PcDescriptors::Handle(zone);
@ -604,9 +665,19 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const bool is_trampoline = data.trampoline_bytes != nullptr;
ASSERT((data.text_offset_ - instructions_[0].text_offset_) == text_offset);
if (bare_instruction_payloads && profile_writer_ != nullptr) {
const intptr_t instructions_sections_offset = Image::kHeaderSize;
const intptr_t offset = section_headers_size + text_offset;
profile_writer_->AttributeReferenceTo(
{offset_space_, instructions_sections_offset},
{{offset_space_, offset},
V8SnapshotProfileWriter::Reference::kElement,
text_offset});
}
if (is_trampoline) {
if (profile_writer_ != nullptr) {
const intptr_t offset = Image::kHeaderSize + text_offset;
const intptr_t offset = section_headers_size + text_offset;
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
"Trampolines",
/*name=*/nullptr);
@ -629,7 +700,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
descriptors = data.code_->pc_descriptors();
if (profile_writer_ != nullptr) {
const intptr_t offset = Image::kHeaderSize + text_offset;
const intptr_t offset = section_headers_size + text_offset;
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
"Instructions",
/*name=*/nullptr);
@ -637,9 +708,12 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
SizeInSnapshot(insns.raw()));
}
const uword payload_start = insns.PayloadStart();
// 1. Write from the object start to the payload start. This includes the
// object header and the fixed fields.
{
// object header and the fixed fields. Not written for AOT snapshots using
// bare instructions.
if (!bare_instruction_payloads) {
NoSafepointScope no_safepoint;
// Write Instructions with the mark and read-only bits set.
@ -656,7 +730,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
#endif
#if defined(IS_SIMARM_X64)
const intptr_t size_in_bytes = InstructionsSizeInSnapshot(insns.Size());
const intptr_t size_in_bytes = InstructionsSizeInSnapshot(insns.raw());
marked_tags = RawObject::SizeTag::update(size_in_bytes * 2, marked_tags);
WriteWordLiteralText(marked_tags);
text_offset += sizeof(compiler::target::uword);
@ -664,7 +738,6 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
text_offset += sizeof(compiler::target::uword);
#else // defined(IS_SIMARM_X64)
uword object_start = reinterpret_cast<uword>(insns.raw_ptr());
uword payload_start = insns.PayloadStart();
WriteWordLiteralText(marked_tags);
object_start += sizeof(uword);
text_offset += sizeof(uword);
@ -683,7 +756,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
}
if (debug_dwarf_ != nullptr) {
auto const virtual_address =
debug_segment_base + Image::kHeaderSize + text_offset;
debug_segment_base + section_headers_size + text_offset;
debug_dwarf_->AddCode(code, virtual_address);
}
#endif
@ -692,19 +765,29 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
assembly_stream_.Print("%s:\n", namer.AssemblyNameFor(dwarf_index, code));
{
// 3. Write from the payload start to payload end.
// 3. Write from the payload start to payload end. For AOT snapshots
// with bare instructions, this is the only part serialized.
NoSafepointScope no_safepoint;
const uword payload_start = insns.PayloadStart();
const uword payload_size =
Utils::RoundUp(insns.Size(), sizeof(compiler::target::uword));
assert(kBareInstructionsAlignment <=
compiler::target::ObjectAlignment::kObjectAlignment);
const auto payload_align = bare_instruction_payloads
? kBareInstructionsAlignment
: sizeof(compiler::target::uword);
const uword payload_size = Utils::RoundUp(insns.Size(), payload_align);
const uword payload_end = payload_start + payload_size;
ASSERT(Utils::IsAligned(text_offset, payload_align));
#if defined(DART_PRECOMPILER)
PcDescriptors::Iterator iterator(descriptors,
RawPcDescriptors::kBSSRelocation);
uword next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1;
for (uword cursor = payload_start; cursor < payload_end;
// We only generate BSS relocations that are word-sized and at
// word-aligned offsets in the payload.
auto const possible_relocations_end =
Utils::RoundDown(payload_end, sizeof(compiler::target::uword));
for (uword cursor = payload_start; cursor < possible_relocations_end;
cursor += sizeof(compiler::target::uword)) {
compiler::target::uword data =
*reinterpret_cast<compiler::target::uword*>(cursor);
@ -716,6 +799,8 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
WriteWordLiteralText(data);
}
}
assert(next_reloc_offset != (possible_relocations_end - payload_start));
WriteByteSequence(possible_relocations_end, payload_end);
text_offset += payload_size;
#else
text_offset += WriteByteSequence(payload_start, payload_end);
@ -723,26 +808,43 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
// 4. Write from the payload end to object end. Note we can't simply copy
// from the object because the host object may have less alignment filler
// than the target object in the cross-word case.
uword unaligned_size =
compiler::target::Instructions::HeaderSize() + payload_size;
uword alignment_size =
Utils::RoundUp(unaligned_size,
compiler::target::ObjectAlignment::kObjectAlignment) -
unaligned_size;
while (alignment_size > 0) {
WriteWordLiteralText(compiler::Assembler::GetBreakInstructionFiller());
alignment_size -= sizeof(compiler::target::uword);
text_offset += sizeof(compiler::target::uword);
}
// than the target object in the cross-word case. Not written for AOT
// snapshots using bare instructions.
if (!bare_instruction_payloads) {
uword unaligned_size =
compiler::target::Instructions::HeaderSize() + payload_size;
uword alignment_size =
Utils::RoundUp(
unaligned_size,
compiler::target::ObjectAlignment::kObjectAlignment) -
unaligned_size;
while (alignment_size > 0) {
WriteWordLiteralText(
compiler::Assembler::GetBreakInstructionFiller());
alignment_size -= sizeof(compiler::target::uword);
text_offset += sizeof(compiler::target::uword);
}
ASSERT(kWordSize != compiler::target::kWordSize ||
(text_offset - instr_start) == insns.raw()->HeapSize());
ASSERT(kWordSize != compiler::target::kWordSize ||
(text_offset - instr_start) == insns.raw()->HeapSize());
}
}
ASSERT((text_offset - instr_start) == SizeInSnapshot(insns.raw()));
}
// Should be a no-op unless writing bare instruction payloads, in which case
// we need to add post-payload padding to the object alignment.
text_offset +=
Align(compiler::target::ObjectAlignment::kObjectAlignment, text_offset);
ASSERT(Image::kHeaderSize +
(bare_instruction_payloads
? compiler::target::InstructionsSection::HeaderSize()
: 0) +
text_offset ==
image_size);
FrameUnwindEpilogue();
#if defined(DART_PRECOMPILER)
@ -763,7 +865,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
// we can pass nullptr for the bytes of the section/segment.
auto const debug_segment_base2 =
debug_dwarf_->elf()->AddText(instructions_symbol, /*bytes=*/nullptr,
Image::kHeaderSize + text_offset);
section_headers_size + text_offset);
ASSERT(debug_segment_base2 == debug_segment_base);
}
@ -788,7 +890,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const char* data_symbol =
vm ? "_kDartVmSnapshotData" : "_kDartIsolateSnapshotData";
assembly_stream_.Print(".globl %s\n", data_symbol);
assembly_stream_.Print(".balign %" Pd ", 0\n", kMaxObjectAlignment);
Align(kMaxObjectAlignment);
assembly_stream_.Print("%s:\n", data_symbol);
uword buffer = reinterpret_cast<uword>(clustered_stream->buffer());
intptr_t length = clustered_stream->bytes_written();
@ -874,13 +976,33 @@ void AssemblyImageWriter::FrameUnwindEpilogue() {
}
intptr_t AssemblyImageWriter::WriteByteSequence(uword start, uword end) {
for (auto* cursor = reinterpret_cast<compiler::target::uword*>(start);
cursor < reinterpret_cast<compiler::target::uword*>(end); cursor++) {
assert(end >= start);
auto const end_of_words =
Utils::RoundDown(end, sizeof(compiler::target::uword));
for (auto cursor = reinterpret_cast<compiler::target::uword*>(start);
cursor < reinterpret_cast<compiler::target::uword*>(end_of_words);
cursor++) {
WriteWordLiteralText(*cursor);
}
if (end != end_of_words) {
auto start_of_rest = reinterpret_cast<const uint8_t*>(end_of_words);
assembly_stream_.Print(".byte ");
for (auto cursor = start_of_rest;
cursor < reinterpret_cast<const uint8_t*>(end); cursor++) {
if (cursor != start_of_rest) assembly_stream_.Print(", ");
assembly_stream_.Print("0x%0.2" Px "", *cursor);
}
assembly_stream_.Print("\n");
}
return end - start;
}
intptr_t AssemblyImageWriter::Align(intptr_t alignment, uword position) {
const uword next_position = Utils::RoundUp(position, alignment);
assembly_stream_.Print(".balign %" Pd ", 0\n", alignment);
return next_position - position;
}
BlobImageWriter::BlobImageWriter(Thread* thread,
uint8_t** instructions_blob_buffer,
ReAlloc alloc,
@ -912,7 +1034,9 @@ intptr_t BlobImageWriter::WriteByteSequence(uword start, uword end) {
}
void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const intptr_t instructions_length = next_text_offset_;
const bool bare_instruction_payloads =
FLAG_precompiled_mode && FLAG_use_bare_instructions;
#ifdef DART_PRECOMPILER
intptr_t segment_base = 0;
if (elf_ != nullptr) {
@ -926,7 +1050,9 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
// This header provides the gap to make the instructions snapshot look like a
// HeapPage.
instructions_blob_stream_.WriteTargetWord(instructions_length);
const intptr_t image_size = Utils::RoundUp(
next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
instructions_blob_stream_.WriteTargetWord(image_size);
#if defined(DART_PRECOMPILER)
instructions_blob_stream_.WriteTargetWord(
elf_ != nullptr ? bss_base_ - segment_base : 0);
@ -939,6 +1065,36 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
instructions_blob_stream_.WriteTargetWord(0);
}
if (bare_instruction_payloads) {
const intptr_t image_payload_length = image_size - Image::kHeaderSize;
// Add the RawInstructionsSection header.
uword marked_tags = 0;
marked_tags = RawObject::OldBit::update(true, marked_tags);
marked_tags = RawObject::OldAndNotRememberedBit::update(true, marked_tags);
marked_tags = RawObject::SizeTag::update(image_payload_length, marked_tags);
marked_tags =
RawObject::ClassIdTag::update(kInstructionsSectionCid, marked_tags);
instructions_blob_stream_.WriteTargetWord(marked_tags);
// Uses next_text_offset_ to avoid any post-payload padding.
const intptr_t instructions_length =
next_text_offset_ - Image::kHeaderSize -
compiler::target::InstructionsSection::HeaderSize();
instructions_blob_stream_.WriteTargetWord(instructions_length);
if (profile_writer_ != nullptr) {
const intptr_t offset = Image::kHeaderSize;
const intptr_t non_instruction_bytes =
compiler::target::InstructionsSection::HeaderSize();
profile_writer_->SetObjectTypeAndName({offset_space_, offset},
"InstructionsSection",
/*name=*/nullptr);
profile_writer_->AttributeBytesTo({offset_space_, offset},
non_instruction_bytes);
profile_writer_->AddRoot({offset_space_, offset});
}
}
intptr_t text_offset = 0;
#if defined(DART_PRECOMPILER)
@ -952,6 +1108,15 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const bool is_trampoline = data.trampoline_bytes != nullptr;
ASSERT((data.text_offset_ - instructions_[0].text_offset_) == text_offset);
if (bare_instruction_payloads && profile_writer_ != nullptr) {
const intptr_t instructions_sections_offset = Image::kHeaderSize;
profile_writer_->AttributeReferenceTo(
{offset_space_, instructions_sections_offset},
{{offset_space_, instructions_blob_stream_.Position()},
V8SnapshotProfileWriter::Reference::kElement,
text_offset});
}
if (is_trampoline) {
const auto start = reinterpret_cast<uword>(data.trampoline_bytes);
const auto end = start + data.trampline_length;
@ -965,17 +1130,9 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const Instructions& insns = *instructions_[i].insns_;
AutoTraceImage(insns, 0, &this->instructions_blob_stream_);
const uword payload_start = insns.PayloadStart();
uword object_start = reinterpret_cast<uword>(insns.raw_ptr());
uword payload_start = insns.PayloadStart();
uword payload_size =
Utils::RoundUp(
compiler::target::Instructions::HeaderSize() + insns.Size(),
compiler::target::ObjectAlignment::kObjectAlignment) -
compiler::target::Instructions::HeaderSize();
uword object_end = payload_start + payload_size;
ASSERT(Utils::IsAligned(payload_start, sizeof(uword)));
ASSERT(Utils::IsAligned(payload_start, sizeof(compiler::target::uword)));
// Write Instructions with the mark and read-only bits set.
uword marked_tags = insns.raw_ptr()->tags_;
@ -989,32 +1146,49 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
marked_tags |= static_cast<uword>(insns.raw_ptr()->hash_) << 32;
#endif
intptr_t payload_stream_start = 0;
#if defined(IS_SIMARM_X64)
const intptr_t start_offset = instructions_blob_stream_.bytes_written();
const intptr_t size_in_bytes = InstructionsSizeInSnapshot(insns.Size());
const intptr_t size_in_bytes = InstructionsSizeInSnapshot(insns.raw());
marked_tags = RawObject::SizeTag::update(size_in_bytes * 2, marked_tags);
instructions_blob_stream_.WriteTargetWord(marked_tags);
instructions_blob_stream_.WriteFixed<uint32_t>(
insns.raw_ptr()->size_and_flags_);
payload_stream_start = instructions_blob_stream_.Position();
if (!bare_instruction_payloads) {
instructions_blob_stream_.WriteTargetWord(marked_tags);
instructions_blob_stream_.WriteFixed<uint32_t>(
insns.raw_ptr()->size_and_flags_);
} else {
ASSERT(Utils::IsAligned(instructions_blob_stream_.Position(),
kBareInstructionsAlignment));
}
const intptr_t payload_stream_start = instructions_blob_stream_.Position();
instructions_blob_stream_.WriteBytes(
reinterpret_cast<const void*>(insns.PayloadStart()), insns.Size());
instructions_blob_stream_.Align(
compiler::target::ObjectAlignment::kObjectAlignment);
const intptr_t alignment =
bare_instruction_payloads
? kBareInstructionsAlignment
: compiler::target::ObjectAlignment::kObjectAlignment;
instructions_blob_stream_.Align(alignment);
const intptr_t end_offset = instructions_blob_stream_.bytes_written();
text_offset += (end_offset - start_offset);
USE(object_start);
USE(object_end);
#else // defined(IS_SIMARM_X64)
payload_stream_start = instructions_blob_stream_.Position() +
(insns.PayloadStart() - object_start);
instructions_blob_stream_.WriteWord(marked_tags);
text_offset += sizeof(uword);
object_start += sizeof(uword);
text_offset += WriteByteSequence(object_start, object_end);
// Only payload is output in AOT snapshots.
const uword header_size =
bare_instruction_payloads
? 0
: compiler::target::Instructions::HeaderSize();
const uword payload_size = SizeInSnapshot(insns.raw()) - header_size;
const uword object_end = payload_start + payload_size;
if (!bare_instruction_payloads) {
uword object_start = reinterpret_cast<uword>(insns.raw_ptr());
instructions_blob_stream_.WriteWord(marked_tags);
text_offset += sizeof(uword);
object_start += sizeof(uword);
text_offset += WriteByteSequence(object_start, payload_start);
} else {
ASSERT(Utils::IsAligned(instructions_blob_stream_.Position(),
kBareInstructionsAlignment));
}
const intptr_t payload_stream_start = instructions_blob_stream_.Position();
text_offset += WriteByteSequence(payload_start, object_end);
#endif
#if defined(DART_PRECOMPILER)
@ -1076,7 +1250,12 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
ImageWriter::SizeInSnapshot(insns.raw()));
}
ASSERT(instructions_blob_stream_.bytes_written() == instructions_length);
// Should be a no-op unless writing bare instruction payloads, in which case
// we need to add post-payload padding to the object alignment.
instructions_blob_stream_.Align(
compiler::target::ObjectAlignment::kObjectAlignment);
ASSERT(instructions_blob_stream_.bytes_written() == image_size);
#ifdef DART_PRECOMPILER
const char* instructions_symbol =
@ -1114,6 +1293,18 @@ RawApiError* ImageReader::VerifyAlignment() const {
return ApiError::null();
}
#if defined(DART_PRECOMPILED_RUNTIME)
uword ImageReader::GetBareInstructionsAt(uint32_t offset) const {
ASSERT(Utils::IsAligned(offset, ImageWriter::kBareInstructionsAlignment));
return reinterpret_cast<uword>(instructions_image_) + offset;
}
uword ImageReader::GetBareInstructionsEnd() const {
Image image(instructions_image_);
return reinterpret_cast<uword>(image.object_start()) + image.object_size();
}
#endif
RawInstructions* ImageReader::GetInstructionsAt(uint32_t offset) const {
ASSERT(Utils::IsAligned(offset, kObjectAlignment));

View file

@ -69,6 +69,8 @@ class ImageReader : public ZoneAllocated {
RawApiError* VerifyAlignment() const;
ONLY_IN_PRECOMPILED(uword GetBareInstructionsAt(uint32_t offset) const);
ONLY_IN_PRECOMPILED(uword GetBareInstructionsEnd() const);
RawInstructions* GetInstructionsAt(uint32_t offset) const;
RawObject* GetObjectAt(uint32_t offset) const;
@ -153,6 +155,9 @@ class ImageWriter : public ValueObject {
void ResetOffsets() {
next_data_offset_ = Image::kHeaderSize;
next_text_offset_ = Image::kHeaderSize;
if (FLAG_use_bare_instructions && FLAG_precompiled_mode) {
next_text_offset_ += compiler::target::InstructionsSection::HeaderSize();
}
objects_.Clear();
instructions_.Clear();
}
@ -179,6 +184,7 @@ class ImageWriter : public ValueObject {
void TraceInstructions(const Instructions& instructions);
static intptr_t SizeInSnapshot(RawObject* object);
static const intptr_t kBareInstructionsAlignment = 4;
protected:
void WriteROData(WriteStream* stream);
@ -329,6 +335,7 @@ class AssemblyImageWriter : public ImageWriter {
void FrameUnwindPrologue();
void FrameUnwindEpilogue();
intptr_t WriteByteSequence(uword start, uword end);
intptr_t Align(intptr_t alignment, uword position = 0);
#if defined(TARGET_ARCH_IS_64_BIT)
const char* kLiteralPrefix = ".quad";

View file

@ -150,6 +150,8 @@ RawClass* Object::kernel_program_info_class_ =
RawClass* Object::code_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::bytecode_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::instructions_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::instructions_section_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::object_pool_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::pc_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::code_source_map_class_ =
@ -793,6 +795,9 @@ void Object::Init(Isolate* isolate) {
cls = Class::New<Instructions, RTN::Instructions>(isolate);
instructions_class_ = cls.raw();
cls = Class::New<InstructionsSection, RTN::InstructionsSection>(isolate);
instructions_section_class_ = cls.raw();
cls = Class::New<ObjectPool, RTN::ObjectPool>(isolate);
object_pool_class_ = cls.raw();
@ -1221,6 +1226,7 @@ void Object::Cleanup() {
code_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
bytecode_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
instructions_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
instructions_section_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
object_pool_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
pc_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
code_source_map_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
@ -1323,6 +1329,7 @@ void Object::FinalizeVMIsolate(Isolate* isolate) {
SET_CLASS_NAME(code, Code);
SET_CLASS_NAME(bytecode, Bytecode);
SET_CLASS_NAME(instructions, Instructions);
SET_CLASS_NAME(instructions_section, InstructionsSection);
SET_CLASS_NAME(object_pool, ObjectPool);
SET_CLASS_NAME(code_source_map, CodeSourceMap);
SET_CLASS_NAME(pc_descriptors, PcDescriptors);
@ -4532,6 +4539,8 @@ const char* Class::GenerateUserVisibleName() const {
return Symbols::Bytecode().ToCString();
case kInstructionsCid:
return Symbols::Instructions().ToCString();
case kInstructionsSectionCid:
return Symbols::InstructionsSection().ToCString();
case kObjectPoolCid:
return Symbols::ObjectPool().ToCString();
case kCodeSourceMapCid:
@ -13104,7 +13113,7 @@ void Library::CheckFunctionFingerprints() {
}
#endif // defined(DEBUG) && !defined(DART_PRECOMPILED_RUNTIME).
RawInstructions* Instructions::New(intptr_t size, bool has_single_entry_point) {
RawInstructions* Instructions::New(intptr_t size, bool has_monomorphic_entry) {
ASSERT(size >= 0);
ASSERT(Object::instructions_class() != Class::null());
if (size < 0 || size > kMaxElements) {
@ -13119,7 +13128,7 @@ RawInstructions* Instructions::New(intptr_t size, bool has_single_entry_point) {
NoSafepointScope no_safepoint;
result ^= raw;
result.SetSize(size);
result.SetHasSingleEntryPoint(has_single_entry_point);
result.SetHasMonomorphicEntry(has_monomorphic_entry);
result.set_stats(nullptr);
}
return result.raw();
@ -13144,6 +13153,10 @@ void Instructions::set_stats(CodeStatistics* stats) const {
#endif
}
const char* InstructionsSection::ToCString() const {
return "InstructionsSection";
}
// Encode integer |value| in SLEB128 format and store into |data|.
static void EncodeSLEB128(GrowableArray<uint8_t>* data, intptr_t value) {
bool is_last_part = false;
@ -15321,12 +15334,11 @@ void Code::Disassemble(DisassemblyFormatter* formatter) const {
if (!FLAG_support_disassembler) {
return;
}
const Instructions& instr = Instructions::Handle(instructions());
uword start = instr.PayloadStart();
const uword start = PayloadStart();
if (formatter == NULL) {
Disassembler::Disassemble(start, start + instr.Size(), *this);
Disassembler::Disassemble(start, start + Size(), *this);
} else {
Disassembler::Disassemble(start, start + instr.Size(), formatter, *this);
Disassembler::Disassemble(start, start + Size(), formatter, *this);
}
#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
}
@ -15466,7 +15478,7 @@ RawCode* Code::FinalizeCode(FlowGraphCompiler* compiler,
assembler->GetSelfHandle() = code.raw();
#endif
Instructions& instrs = Instructions::ZoneHandle(Instructions::New(
assembler->CodeSize(), assembler->has_single_entry_point()));
assembler->CodeSize(), assembler->has_monomorphic_entry()));
{
// Important: if GC is triggerred at any point between Instructions::New
@ -15867,11 +15879,10 @@ void Code::DumpSourcePositions(bool relative_addresses) const {
bool Code::VerifyBSSRelocations() const {
const auto& descriptors = PcDescriptors::Handle(pc_descriptors());
const auto& insns = Instructions::Handle(instructions());
PcDescriptors::Iterator iterator(descriptors,
RawPcDescriptors::kBSSRelocation);
while (iterator.MoveNext()) {
const uword reloc = insns.PayloadStart() + iterator.PcOffset();
const uword reloc = PayloadStart() + iterator.PcOffset();
const word target = *reinterpret_cast<word*>(reloc);
// The relocation is in its original unpatched form -- the addend
// representing the target symbol itself.

View file

@ -482,6 +482,9 @@ class Object {
static RawClass* code_class() { return code_class_; }
static RawClass* bytecode_class() { return bytecode_class_; }
static RawClass* instructions_class() { return instructions_class_; }
static RawClass* instructions_section_class() {
return instructions_section_class_;
}
static RawClass* object_pool_class() { return object_pool_class_; }
static RawClass* pc_descriptors_class() { return pc_descriptors_class_; }
static RawClass* code_source_map_class() { return code_source_map_class_; }
@ -766,6 +769,8 @@ class Object {
static RawClass* code_class_; // Class of the Code vm object.
static RawClass* bytecode_class_; // Class of the Bytecode vm object.
static RawClass* instructions_class_; // Class of the Instructions vm object.
static RawClass*
instructions_section_class_; // Class of InstructionsSection.
static RawClass* object_pool_class_; // Class of the ObjectPool vm object.
static RawClass* pc_descriptors_class_; // Class of PcDescriptors vm object.
static RawClass* code_source_map_class_; // Class of CodeSourceMap vm object.
@ -5039,21 +5044,13 @@ class Instructions : public Object {
return SizeBits::decode(instr->ptr()->size_and_flags_);
}
bool HasSingleEntryPoint() const {
bool HasMonomorphicEntry() const {
return FlagsBits::decode(raw_ptr()->size_and_flags_);
}
static bool HasSingleEntryPoint(const RawInstructions* instr) {
static bool HasMonomorphicEntry(const RawInstructions* instr) {
return FlagsBits::decode(instr->ptr()->size_and_flags_);
}
static bool ContainsPc(RawInstructions* instruction, uword pc) {
const uword offset = pc - PayloadStart(instruction);
// We use <= instead of < here because the saved-pc can be outside the
// instruction stream if the last instruction is a call we don't expect to
// return (e.g. because it throws an exception).
return offset <= static_cast<uword>(Size(instruction));
}
uword PayloadStart() const { return PayloadStart(raw()); }
uword MonomorphicEntryPoint() const { return MonomorphicEntryPoint(raw()); }
uword EntryPoint() const { return EntryPoint(raw()); }
@ -5089,7 +5086,7 @@ class Instructions : public Object {
static uword MonomorphicEntryPoint(const RawInstructions* instr) {
uword entry = PayloadStart(instr);
if (!HasSingleEntryPoint(instr)) {
if (HasMonomorphicEntry(instr)) {
entry += !FLAG_precompiled_mode ? kMonomorphicEntryOffsetJIT
: kMonomorphicEntryOffsetAOT;
}
@ -5098,7 +5095,7 @@ class Instructions : public Object {
static uword EntryPoint(const RawInstructions* instr) {
uword entry = PayloadStart(instr);
if (!HasSingleEntryPoint(instr)) {
if (HasMonomorphicEntry(instr)) {
entry += !FLAG_precompiled_mode ? kPolymorphicEntryOffsetJIT
: kPolymorphicEntryOffsetAOT;
}
@ -5148,7 +5145,7 @@ class Instructions : public Object {
SizeBits::update(value, raw_ptr()->size_and_flags_));
}
void SetHasSingleEntryPoint(bool value) const {
void SetHasMonomorphicEntry(bool value) const {
StoreNonPointer(&raw_ptr()->size_and_flags_,
FlagsBits::update(value, raw_ptr()->size_and_flags_));
}
@ -5157,7 +5154,7 @@ class Instructions : public Object {
// only be created using the Code::FinalizeCode method. This method creates
// the RawInstruction and RawCode objects, sets up the pointer offsets
// and links the two in a GC safe manner.
static RawInstructions* New(intptr_t size, bool has_single_entry_point);
static RawInstructions* New(intptr_t size, bool has_monomorphic_entry);
FINAL_HEAP_OBJECT_IMPLEMENTATION(Instructions, Object);
friend class Class;
@ -5167,6 +5164,34 @@ class Instructions : public Object {
friend class ImageWriter;
};
// Used only to provide memory accounting for the bare instruction payloads
// we serialize, since they are no longer part of RawInstructions objects.
class InstructionsSection : public Object {
public:
// Excludes HeaderSize().
intptr_t Size() const { return raw_ptr()->payload_length_; }
static intptr_t Size(const RawInstructionsSection* instr) {
return instr->ptr()->payload_length_;
}
static intptr_t InstanceSize() {
ASSERT(sizeof(RawInstructionsSection) ==
OFFSET_OF_RETURNED_VALUE(RawInstructionsSection, data));
return 0;
}
static intptr_t InstanceSize(intptr_t size) {
return Utils::RoundUp(HeaderSize() + size, kObjectAlignment);
}
static intptr_t HeaderSize() {
return Utils::RoundUp(sizeof(RawInstructionsSection), kWordSize);
}
private:
FINAL_HEAP_OBJECT_IMPLEMENTATION(InstructionsSection, Object);
friend class Class;
};
class LocalVarDescriptors : public Object {
public:
intptr_t Length() const;
@ -5542,11 +5567,6 @@ class Code : public Object {
return code->ptr()->instructions_;
}
// Returns the entry point of [InstructionsOf(code)].
static uword EntryPointOf(const RawCode* code) {
return Instructions::EntryPoint(InstructionsOf(code));
}
static intptr_t saved_instructions_offset() {
return OFFSET_OF(RawCode, instructions_);
}
@ -5596,12 +5616,38 @@ class Code : public Object {
bool is_alive() const { return AliveBit::decode(raw_ptr()->state_bits_); }
void set_is_alive(bool value) const;
// Returns the payload start of [instructions()].
uword PayloadStart() const {
return Instructions::PayloadStart(instructions());
bool HasMonomorphicEntry() const { return HasMonomorphicEntry(raw()); }
static bool HasMonomorphicEntry(const RawCode* code) {
#if defined(DART_PRECOMPILED_RUNTIME)
return code->ptr()->entry_point_ != code->ptr()->monomorphic_entry_point_;
#else
return Instructions::HasMonomorphicEntry(InstructionsOf(code));
#endif
}
// Returns the payload start of [instructions()].
uword PayloadStart() const { return PayloadStartOf(raw()); }
static uword PayloadStartOf(const RawCode* code) {
#if defined(DART_PRECOMPILED_RUNTIME)
const uword entry_offset = HasMonomorphicEntry(code)
? Instructions::kPolymorphicEntryOffsetAOT
: 0;
return EntryPointOf(code) - entry_offset;
#else
return Instructions::PayloadStart(InstructionsOf(code));
#endif
}
// Returns the entry point of [instructions()].
uword EntryPoint() const { return Instructions::EntryPoint(instructions()); }
uword EntryPoint() const { return EntryPointOf(raw()); }
static uword EntryPointOf(const RawCode* code) {
#if defined(DART_PRECOMPILED_RUNTIME)
return code->ptr()->entry_point_;
#else
return Instructions::EntryPoint(InstructionsOf(code));
#endif
}
// Returns the unchecked entry point of [instructions()].
uword UncheckedEntryPoint() const {
#if defined(DART_PRECOMPILED_RUNTIME)
@ -5612,7 +5658,11 @@ class Code : public Object {
}
// Returns the monomorphic entry point of [instructions()].
uword MonomorphicEntryPoint() const {
#if defined(DART_PRECOMPILED_RUNTIME)
return raw_ptr()->monomorphic_entry_point_;
#else
return Instructions::MonomorphicEntryPoint(instructions());
#endif
}
// Returns the unchecked monomorphic entry point of [instructions()].
uword MonomorphicUncheckedEntryPoint() const {
@ -5622,8 +5672,16 @@ class Code : public Object {
return MonomorphicEntryPoint() + raw_ptr()->unchecked_offset_;
#endif
}
// Returns the size of [instructions()].
intptr_t Size() const { return Instructions::Size(instructions()); }
intptr_t Size() const { return PayloadSizeOf(raw()); }
static intptr_t PayloadSizeOf(const RawCode* code) {
#if defined(DART_PRECOMPILED_RUNTIME)
return code->ptr()->instructions_length_;
#else
return Instructions::Size(InstructionsOf(code));
#endif
}
RawObjectPool* GetObjectPool() const;
// Returns whether the given PC address is in [instructions()].
@ -5632,8 +5690,8 @@ class Code : public Object {
}
// Returns whether the given PC address is in [InstructionsOf(code)].
static bool ContainsInstructionAt(const RawCode* code, uword addr) {
return Instructions::ContainsPc(InstructionsOf(code), addr);
static bool ContainsInstructionAt(const RawCode* code, uword pc) {
return RawCode::ContainsPC(code, pc);
}
// Returns true if there is a debugger breakpoint set in this code object.
@ -6037,11 +6095,13 @@ class Code : public Object {
// Returns the unchecked entry point offset for [instructions_].
uint32_t UncheckedEntryPointOffset() const {
return UncheckedEntryPointOffsetOf(raw());
}
static uint32_t UncheckedEntryPointOffsetOf(RawCode* code) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
return raw_ptr()->unchecked_entry_point_ - raw_ptr()->entry_point_;
#else
return raw_ptr()->unchecked_offset_;
return code->ptr()->unchecked_offset_;
#endif
}
@ -6079,6 +6139,7 @@ class Code : public Object {
friend class FunctionSerializationCluster;
friend class CodeSerializationCluster;
friend class CodeDeserializationCluster;
friend class Deserializer; // for InitializeCachedEntryPointsFrom
friend class StubCode; // for set_object_pool
friend class MegamorphicCacheTable; // for set_object_pool
friend class CodePatcher; // for set_instructions

View file

@ -667,6 +667,10 @@ void Instructions::PrintJSONImpl(JSONStream* stream, bool ref) const {
}
}
void InstructionsSection::PrintJSONImpl(JSONStream* stream, bool ref) const {
Object::PrintJSONImpl(stream, ref);
}
void ObjectPool::PrintJSONImpl(JSONStream* stream, bool ref) const {
JSONObject jsobj(stream);
AddCommonObjectProperties(&jsobj, "Object", ref);

View file

@ -100,6 +100,13 @@ intptr_t RawObject::HeapSizeFromClass() const {
instance_size = Instructions::InstanceSize(instructions_size);
break;
}
case kInstructionsSectionCid: {
const RawInstructionsSection* raw_section =
reinterpret_cast<const RawInstructionsSection*>(this);
intptr_t section_size = InstructionsSection::Size(raw_section);
instance_size = InstructionsSection::InstanceSize(section_size);
break;
}
case kContextCid: {
const RawContext* raw_context = reinterpret_cast<const RawContext*>(this);
intptr_t num_variables = raw_context->ptr()->num_variables_;
@ -549,6 +556,7 @@ NULL_VISITOR(TransferableTypedData)
REGULAR_VISITOR(Pointer)
NULL_VISITOR(DynamicLibrary)
VARIABLE_NULL_VISITOR(Instructions, Instructions::Size(raw_obj))
VARIABLE_NULL_VISITOR(InstructionsSection, InstructionsSection::Size(raw_obj))
VARIABLE_NULL_VISITOR(PcDescriptors, raw_obj->ptr()->length_)
VARIABLE_NULL_VISITOR(CodeSourceMap, raw_obj->ptr()->length_)
VARIABLE_NULL_VISITOR(CompressedStackMaps, raw_obj->ptr()->payload_size())
@ -564,12 +572,12 @@ UNREACHABLE_VISITOR(String)
// Smi has no heap representation.
UNREACHABLE_VISITOR(Smi)
bool RawCode::ContainsPC(RawObject* raw_obj, uword pc) {
if (raw_obj->IsCode()) {
RawCode* raw_code = static_cast<RawCode*>(raw_obj);
return RawInstructions::ContainsPC(raw_code->ptr()->instructions_, pc);
}
return false;
bool RawCode::ContainsPC(const RawObject* raw_obj, uword pc) {
if (!raw_obj->IsCode()) return false;
auto const raw_code = static_cast<const RawCode*>(raw_obj);
const uword start = Code::PayloadStartOf(raw_code);
const uword size = Code::PayloadSizeOf(raw_code);
return (pc - start) <= size; // pc may point just past last instruction.
}
intptr_t RawCode::VisitCodePointers(RawCode* raw_obj,
@ -583,8 +591,7 @@ intptr_t RawCode::VisitCodePointers(RawCode* raw_obj,
// instructions. The variable portion of a Code object describes where to
// find those pointers for tracing.
if (Code::AliveBit::decode(obj->state_bits_)) {
uword entry_point = reinterpret_cast<uword>(obj->instructions_->ptr()) +
Instructions::HeaderSize();
uword entry_point = Code::PayloadStartOf(raw_obj);
for (intptr_t i = 0; i < length; i++) {
int32_t offset = obj->data()[i];
visitor->VisitPointer(
@ -626,12 +633,13 @@ intptr_t RawObjectPool::VisitObjectPoolPointers(RawObjectPool* raw_obj,
return ObjectPool::InstanceSize(length);
}
bool RawInstructions::ContainsPC(RawInstructions* raw_instr, uword pc) {
uword start_pc =
reinterpret_cast<uword>(raw_instr->ptr()) + Instructions::HeaderSize();
uword end_pc = start_pc + Instructions::Size(raw_instr);
ASSERT(end_pc > start_pc);
return (pc >= start_pc) && (pc < end_pc);
bool RawInstructions::ContainsPC(const RawInstructions* raw_instr, uword pc) {
const uword start = Instructions::PayloadStart(raw_instr);
const uword size = Instructions::Size(raw_instr);
// We use <= instead of < here because the saved-pc can be outside the
// instruction stream if the last instruction is a call we don't expect to
// return (e.g. because it throws an exception).
return (pc - start) <= size;
}
intptr_t RawInstance::VisitInstancePointers(RawInstance* raw_obj,

View file

@ -1408,8 +1408,11 @@ class RawKernelProgramInfo : public RawObject {
class RawCode : public RawObject {
RAW_HEAP_OBJECT_IMPLEMENTATION(Code);
// When in the precompiled runtime, there is no active_instructions_ field
// and the entry point caches should contain entry points for instructions_.
// When in the precompiled runtime, there is no disabling of Code objects
// and thus no active_instructions_ field. Thus, the entry point caches are
// only set once during deserialization. If not using bare instructions,
// the caches should match the entry points for instructions_.
//
// Otherwise, they should contain entry points for active_instructions_.
uword entry_point_; // Accessed from generated code.
@ -1497,12 +1500,14 @@ class RawCode : public RawObject {
// Caches the unchecked entry point offset for instructions_, in case we need
// to reset the active_instructions_ to instructions_.
NOT_IN_PRECOMPILED(uint32_t unchecked_offset_);
// Stores the instructions length when not using RawInstructions objects.
ONLY_IN_PRECOMPILED(uint32_t instructions_length_);
// Variable length data follows here.
int32_t* data() { OPEN_ARRAY_START(int32_t, int32_t); }
const int32_t* data() const { OPEN_ARRAY_START(int32_t, int32_t); }
static bool ContainsPC(RawObject* raw_obj, uword pc);
static bool ContainsPC(const RawObject* raw_obj, uword pc);
friend class Function;
template <bool>
@ -1584,7 +1589,7 @@ class RawInstructions : public RawObject {
// Private helper function used while visiting stack frames. The
// code which iterates over dart frames is also called during GC and
// is not allowed to create handles.
static bool ContainsPC(RawInstructions* raw_instr, uword pc);
static bool ContainsPC(const RawInstructions* raw_instr, uword pc);
friend class RawCode;
friend class RawFunction;
@ -1599,6 +1604,19 @@ class RawInstructions : public RawObject {
friend class BlobImageWriter;
};
// Used only to provide memory accounting for the bare instruction payloads
// we serialize, since they are no longer part of RawInstructions objects.
class RawInstructionsSection : public RawObject {
RAW_HEAP_OBJECT_IMPLEMENTATION(InstructionsSection);
VISIT_NOTHING();
// Instructions section payload length in bytes.
uint32_t payload_length_;
// Variable length data follows here.
uint8_t* data() { OPEN_ARRAY_START(uint8_t, uint8_t); }
};
class RawPcDescriptors : public RawObject {
public:
// The macro argument V is passed two arguments, the raw name of the enum value
@ -2974,8 +2992,9 @@ inline bool RawObject::IsVariableSizeClassId(intptr_t index) {
RawObject::IsTwoByteStringClassId(index) ||
RawObject::IsTypedDataClassId(index) || (index == kContextCid) ||
(index == kTypeArgumentsCid) || (index == kInstructionsCid) ||
(index == kObjectPoolCid) || (index == kPcDescriptorsCid) ||
(index == kCodeSourceMapCid) || (index == kCompressedStackMapsCid) ||
(index == kInstructionsSectionCid) || (index == kObjectPoolCid) ||
(index == kPcDescriptorsCid) || (index == kCodeSourceMapCid) ||
(index == kCompressedStackMapsCid) ||
(index == kLocalVarDescriptorsCid) ||
(index == kExceptionHandlersCid) || (index == kCodeCid) ||
(index == kContextScopeCid) || (index == kInstanceCid) ||

View file

@ -541,6 +541,7 @@ MESSAGE_SNAPSHOT_UNREACHABLE(Field);
MESSAGE_SNAPSHOT_UNREACHABLE(Function);
MESSAGE_SNAPSHOT_UNREACHABLE(ICData);
MESSAGE_SNAPSHOT_UNREACHABLE(Instructions);
MESSAGE_SNAPSHOT_UNREACHABLE(InstructionsSection);
MESSAGE_SNAPSHOT_UNREACHABLE(KernelProgramInfo);
MESSAGE_SNAPSHOT_UNREACHABLE(Library);
MESSAGE_SNAPSHOT_UNREACHABLE(LibraryPrefix);

View file

@ -11,13 +11,11 @@ namespace dart {
#if defined(DART_PRECOMPILED_RUNTIME)
static uword BeginPcFromCode(const RawCode* code) {
auto instr = Code::InstructionsOf(code);
return Instructions::PayloadStart(instr);
return Code::PayloadStartOf(code);
}
static uword EndPcFromCode(const RawCode* code) {
auto instr = Code::InstructionsOf(code);
return Instructions::PayloadStart(instr) + Instructions::Size(instr);
return Code::PayloadStartOf(code) + Code::PayloadSizeOf(code);
}
void ReversePcLookupCache::BuildAndAttachToIsolate(Isolate* isolate) {

View file

@ -66,7 +66,11 @@ class ReversePcLookupCache {
}
// Looks up the [Code] object from a given [pc].
inline RawCode* Lookup(uword pc) {
//
// If [is_return_address] is true, then the PC may be immediately after the
// payload, if the last instruction is a call that is guaranteed not to
// return. Otherwise, the PC must be within the payload.
inline RawCode* Lookup(uword pc, bool is_return_address = false) {
NoSafepointScope no_safepoint_scope;
intptr_t left = 0;
@ -81,6 +85,14 @@ class ReversePcLookupCache {
uword middle_pc = pc_array_[middle];
if (middle_pc < pc_offset) {
left = middle + 1;
} else if (!is_return_address && middle_pc == pc_offset) {
// This case should only happen if we have bare instruction payloads.
// Otherwise, the instruction payloads of two RawInstructions objects
// will never be immediately adjacent in memory due to the header of
// the second object.
ASSERT(FLAG_use_bare_instructions);
left = middle + 1;
break;
} else {
right = middle;
}
@ -116,7 +128,9 @@ class ReversePcLookupCache {
inline bool Contains(uword pc) { return false; }
inline RawCode* Lookup(uword pc) { UNREACHABLE(); }
inline RawCode* Lookup(uword pc, bool is_return_address = false) {
UNREACHABLE();
}
};
#endif // defined(DART_PRECOMPILED_RUNTIME

View file

@ -126,7 +126,7 @@ bool StackFrame::IsBareInstructionsDartFrame() const {
if (auto isolate = IsolateOfBareInstructionsFrame()) {
Code code;
auto rct = isolate->reverse_pc_lookup_cache();
code = rct->Lookup(pc());
code = rct->Lookup(pc(), /*is_return_address=*/true);
const intptr_t cid = code.owner()->GetClassId();
ASSERT(cid == kNullCid || cid == kClassCid || cid == kFunctionCid);
@ -141,7 +141,7 @@ bool StackFrame::IsBareInstructionsStubFrame() const {
if (auto isolate = IsolateOfBareInstructionsFrame()) {
Code code;
auto rct = isolate->reverse_pc_lookup_cache();
code = rct->Lookup(pc());
code = rct->Lookup(pc(), /*is_return_address=*/true);
const intptr_t cid = code.owner()->GetClassId();
ASSERT(cid == kNullCid || cid == kClassCid || cid == kFunctionCid);
@ -253,7 +253,8 @@ void StackFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
Code code;
if (auto isolate = IsolateOfBareInstructionsFrame()) {
code = isolate->reverse_pc_lookup_cache()->Lookup(pc());
auto const rct = isolate->reverse_pc_lookup_cache();
code = rct->Lookup(pc(), /*is_return_address=*/true);
} else {
RawObject* pc_marker = *(reinterpret_cast<RawObject**>(
fp() + ((is_interpreted() ? kKBCPcMarkerSlotFromFp
@ -387,7 +388,8 @@ RawCode* StackFrame::LookupDartCode() const {
NoSafepointScope no_safepoint;
#endif
if (auto isolate = IsolateOfBareInstructionsFrame()) {
return isolate->reverse_pc_lookup_cache()->Lookup(pc());
auto const rct = isolate->reverse_pc_lookup_cache();
return rct->Lookup(pc(), /*is_return_address=*/true);
}
RawCode* code = GetCodeObject();
@ -401,7 +403,8 @@ RawCode* StackFrame::LookupDartCode() const {
RawCode* StackFrame::GetCodeObject() const {
ASSERT(!is_interpreted());
if (auto isolate = IsolateOfBareInstructionsFrame()) {
return isolate->reverse_pc_lookup_cache()->Lookup(pc());
auto const rct = isolate->reverse_pc_lookup_cache();
return rct->Lookup(pc(), /*is_return_address=*/true);
} else {
RawObject* pc_marker = *(reinterpret_cast<RawObject**>(
fp() + runtime_frame_layout.code_from_fp * kWordSize));

View file

@ -178,6 +178,7 @@ class ObjectPointerVisitor;
V(IndexToken, "[]") \
V(InitPrefix, "init:") \
V(Instructions, "Instructions") \
V(InstructionsSection, "InstructionsSection") \
V(Int, "int") \
V(Int16List, "Int16List") \
V(Int32List, "Int32List") \