[vm/aot] Discard Code objects from the heap
While deserializing AOT snapshot, Code objects which do not contain valuable information besides entry point and stack maps are discarded and not allocated on the heap (they are replaced with StubCode::UnknownDartCode()). PC -> Code/CompressedStackMaps lookup is implemented using a separate table (InstructionsTable). Flutter gallery in release-sizeopt mode: Heap size of snapshot objects: arm -26.89%, arm64 -27.68% Large Flutter application in release mode with --dwarf-stack-traces: Heap size of snapshot objects: -24.3%. Discarded Code objects: 72.5% of all Code objects. Issue: https://github.com/dart-lang/sdk/issues/44852. TEST=existing tests; "--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects" mode is enabled for a few tests. Change-Id: I5fe3e283630c8e8f4442319d5dcae38d174dd0d8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/189560 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
05a0508e7c
commit
5129cff930
@@ -32,6 +32,7 @@ typedef uint16_t ClassIdTagType;
|
||||
V(Code) \
|
||||
V(Instructions) \
|
||||
V(InstructionsSection) \
|
||||
V(InstructionsTable) \
|
||||
V(ObjectPool) \
|
||||
V(PcDescriptors) \
|
||||
V(CodeSourceMap) \
|
||||
@@ -420,7 +421,8 @@ inline bool IsVariableSizeClassId(intptr_t index) {
|
||||
IsOneByteStringClassId(index) || IsTwoByteStringClassId(index) ||
|
||||
IsTypedDataClassId(index) || (index == kContextCid) ||
|
||||
(index == kTypeArgumentsCid) || (index == kInstructionsCid) ||
|
||||
(index == kInstructionsSectionCid) || (index == kObjectPoolCid) ||
|
||||
(index == kInstructionsSectionCid) ||
|
||||
(index == kInstructionsTableCid) || (index == kObjectPoolCid) ||
|
||||
(index == kPcDescriptorsCid) || (index == kCodeSourceMapCid) ||
|
||||
(index == kCompressedStackMapsCid) ||
|
||||
(index == kLocalVarDescriptorsCid) ||
|
||||
|
||||
@@ -976,8 +976,21 @@ class FunctionDeserializationCluster : public DeserializationCluster {
|
||||
Function::InstanceSize());
|
||||
ReadFromTo(func);
|
||||
|
||||
#if defined(DEBUG)
|
||||
func->untag()->entry_point_ = 0;
|
||||
func->untag()->unchecked_entry_point_ = 0;
|
||||
#endif
|
||||
|
||||
if (kind == Snapshot::kFullAOT) {
|
||||
func->untag()->code_ = static_cast<CodePtr>(d->ReadRef());
|
||||
const intptr_t code_index = d->ReadUnsigned();
|
||||
CodePtr code = static_cast<CodePtr>(d->Ref(code_index));
|
||||
func->untag()->code_ = code;
|
||||
if (Code::IsUnknownDartCode(code)) {
|
||||
const uword entry_point = d->instructions_table().EntryPointAt(
|
||||
code_index - d->code_start_index());
|
||||
func->untag()->entry_point_ = entry_point;
|
||||
func->untag()->unchecked_entry_point_ = entry_point;
|
||||
}
|
||||
} else if (kind == Snapshot::kFullJIT) {
|
||||
NOT_IN_PRECOMPILED(func->untag()->unoptimized_code_ =
|
||||
static_cast<CodePtr>(d->ReadRef()));
|
||||
@@ -985,11 +998,6 @@ class FunctionDeserializationCluster : public DeserializationCluster {
|
||||
func->untag()->ic_data_array_ = static_cast<ArrayPtr>(d->ReadRef());
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
func->untag()->entry_point_ = 0;
|
||||
func->untag()->unchecked_entry_point_ = 0;
|
||||
#endif
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (kind != Snapshot::kFullAOT) {
|
||||
func->untag()->token_pos_ = d->ReadTokenPosition();
|
||||
@@ -1021,13 +1029,16 @@ class FunctionDeserializationCluster : public DeserializationCluster {
|
||||
for (intptr_t i = start_index_; i < stop_index_; i++) {
|
||||
func ^= refs.At(i);
|
||||
ASSERT(func.ptr()->untag()->code()->IsCode());
|
||||
uword entry_point = func.ptr()->untag()->code()->untag()->entry_point_;
|
||||
ASSERT(entry_point != 0);
|
||||
func.ptr()->untag()->entry_point_ = entry_point;
|
||||
uword unchecked_entry_point =
|
||||
func.ptr()->untag()->code()->untag()->unchecked_entry_point_;
|
||||
ASSERT(unchecked_entry_point != 0);
|
||||
func.ptr()->untag()->unchecked_entry_point_ = unchecked_entry_point;
|
||||
if (!Code::IsUnknownDartCode(func.ptr()->untag()->code())) {
|
||||
uword entry_point =
|
||||
func.ptr()->untag()->code()->untag()->entry_point_;
|
||||
ASSERT(entry_point != 0);
|
||||
func.ptr()->untag()->entry_point_ = entry_point;
|
||||
uword unchecked_entry_point =
|
||||
func.ptr()->untag()->code()->untag()->unchecked_entry_point_;
|
||||
ASSERT(unchecked_entry_point != 0);
|
||||
func.ptr()->untag()->unchecked_entry_point_ = unchecked_entry_point;
|
||||
}
|
||||
}
|
||||
} else if (d->kind() == Snapshot::kFullJIT) {
|
||||
Function& func = Function::Handle(d->zone());
|
||||
@@ -1743,8 +1754,7 @@ class KernelProgramInfoDeserializationCluster : public DeserializationCluster {
|
||||
class CodeSerializationCluster : public SerializationCluster {
|
||||
public:
|
||||
explicit CodeSerializationCluster(Heap* heap)
|
||||
: SerializationCluster("Code", compiler::target::Code::InstanceSize()),
|
||||
array_(Array::Handle()) {}
|
||||
: SerializationCluster("Code"), array_(Array::Handle()) {}
|
||||
~CodeSerializationCluster() {}
|
||||
|
||||
void Trace(Serializer* s, ObjectPtr object) {
|
||||
@@ -1898,14 +1908,22 @@ class CodeSerializationCluster : public SerializationCluster {
|
||||
const intptr_t count = objects_.length();
|
||||
s->WriteUnsigned(count);
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
CodePtr code = objects_[i];
|
||||
s->AssignRef(code);
|
||||
WriteAlloc(s, objects_[i]);
|
||||
}
|
||||
const intptr_t deferred_count = deferred_objects_.length();
|
||||
s->WriteUnsigned(deferred_count);
|
||||
for (intptr_t i = 0; i < deferred_count; i++) {
|
||||
CodePtr code = deferred_objects_[i];
|
||||
s->AssignRef(code);
|
||||
WriteAlloc(s, deferred_objects_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteAlloc(Serializer* s, CodePtr code) {
|
||||
s->AssignRef(code);
|
||||
AutoTraceObjectName(code, MakeDisambiguatedCodeName(s, code));
|
||||
const int32_t state_bits = code->untag()->state_bits_;
|
||||
s->Write<int32_t>(state_bits);
|
||||
if (!Code::DiscardedBit::decode(state_bits)) {
|
||||
target_memory_size_ += compiler::target::Code::InstanceSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1951,14 +1969,6 @@ class CodeSerializationCluster : public SerializationCluster {
|
||||
active_unchecked_offset, code, deferred);
|
||||
}
|
||||
|
||||
if (s->InCurrentLoadingUnit(code->untag()->compressed_stackmaps_)) {
|
||||
WriteField(code, compressed_stackmaps_);
|
||||
} else {
|
||||
WriteFieldValue(compressed_stackmaps_, CompressedStackMaps::null());
|
||||
}
|
||||
|
||||
s->Write<int32_t>(code->untag()->state_bits_);
|
||||
|
||||
#if defined(DART_PRECOMPILER)
|
||||
if (FLAG_write_v8_snapshot_profile_to != nullptr) {
|
||||
// If we are writing V8 snapshot profile then attribute references going
|
||||
@@ -2023,6 +2033,11 @@ class CodeSerializationCluster : public SerializationCluster {
|
||||
WriteField(code, exception_handlers_);
|
||||
WriteField(code, pc_descriptors_);
|
||||
WriteField(code, catch_entry_);
|
||||
if (s->InCurrentLoadingUnit(code->untag()->compressed_stackmaps_)) {
|
||||
WriteField(code, compressed_stackmaps_);
|
||||
} else {
|
||||
WriteFieldValue(compressed_stackmaps_, CompressedStackMaps::null());
|
||||
}
|
||||
if (FLAG_precompiled_mode && FLAG_dwarf_stack_traces_mode) {
|
||||
WriteFieldValue(inlined_id_to_function_, Array::null());
|
||||
WriteFieldValue(code_source_map_, CodeSourceMap::null());
|
||||
@@ -2097,21 +2112,33 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
||||
void ReadAlloc(Deserializer* d, bool stamp_canonical) {
|
||||
PageSpace* old_space = d->heap()->old_space();
|
||||
start_index_ = d->next_index();
|
||||
d->set_code_start_index(start_index_);
|
||||
const intptr_t count = d->ReadUnsigned();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
auto code = AllocateUninitialized(old_space, Code::InstanceSize(0));
|
||||
d->AssignRef(code);
|
||||
ReadAllocOneCode(d, old_space);
|
||||
}
|
||||
stop_index_ = d->next_index();
|
||||
deferred_start_index_ = d->next_index();
|
||||
const intptr_t deferred_count = d->ReadUnsigned();
|
||||
for (intptr_t i = 0; i < deferred_count; i++) {
|
||||
auto code = AllocateUninitialized(old_space, Code::InstanceSize(0));
|
||||
d->AssignRef(code);
|
||||
ReadAllocOneCode(d, old_space);
|
||||
}
|
||||
deferred_stop_index_ = d->next_index();
|
||||
}
|
||||
|
||||
void ReadAllocOneCode(Deserializer* d, PageSpace* old_space) {
|
||||
const int32_t state_bits = d->Read<int32_t>();
|
||||
if (Code::DiscardedBit::decode(state_bits)) {
|
||||
ASSERT(StubCode::HasBeenInitialized());
|
||||
d->AssignRef(StubCode::UnknownDartCode().ptr());
|
||||
} else {
|
||||
auto code = static_cast<CodePtr>(
|
||||
AllocateUninitialized(old_space, Code::InstanceSize(0)));
|
||||
d->AssignRef(code);
|
||||
code->untag()->state_bits_ = state_bits;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadFill(Deserializer* d, bool stamp_canonical) {
|
||||
ASSERT(!stamp_canonical); // Never canonical.
|
||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||
@@ -2124,23 +2151,19 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
||||
|
||||
void ReadFill(Deserializer* d, intptr_t id, bool deferred) {
|
||||
auto const code = static_cast<CodePtr>(d->Ref(id));
|
||||
Deserializer::InitializeHeader(code, kCodeCid, Code::InstanceSize(0));
|
||||
|
||||
d->ReadInstructions(code, deferred);
|
||||
|
||||
code->untag()->compressed_stackmaps_ =
|
||||
static_cast<CompressedStackMapsPtr>(d->ReadRef());
|
||||
code->untag()->state_bits_ = d->Read<int32_t>();
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (Code::IsDiscarded(code)) {
|
||||
code->untag()->owner_ = Smi::New(kFunctionCid);
|
||||
if (Code::IsUnknownDartCode(code)) {
|
||||
d->ReadInstructions(code, deferred, /*discarded=*/true);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
ASSERT(!Code::IsDiscarded(code));
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
Deserializer::InitializeHeader(code, kCodeCid, Code::InstanceSize(0));
|
||||
ASSERT(!Code::IsDiscarded(code));
|
||||
|
||||
d->ReadInstructions(code, deferred, /*discarded=*/false);
|
||||
|
||||
// There would be a single global pool if this is a full AOT snapshot
|
||||
// with bare instructions.
|
||||
if (!(d->kind() == Snapshot::kFullAOT && FLAG_use_bare_instructions)) {
|
||||
@@ -2154,6 +2177,8 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
||||
code->untag()->pc_descriptors_ =
|
||||
static_cast<PcDescriptorsPtr>(d->ReadRef());
|
||||
code->untag()->catch_entry_ = d->ReadRef();
|
||||
code->untag()->compressed_stackmaps_ =
|
||||
static_cast<CompressedStackMapsPtr>(d->ReadRef());
|
||||
code->untag()->inlined_id_to_function_ =
|
||||
static_cast<ArrayPtr>(d->ReadRef());
|
||||
code->untag()->code_source_map_ =
|
||||
@@ -2178,7 +2203,7 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
||||
}
|
||||
|
||||
void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
|
||||
d->EndInstructions(refs, start_index_, stop_index_);
|
||||
d->EndInstructions();
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
if (!CodeObservers::AreActive() && !FLAG_support_disassembler) return;
|
||||
@@ -5975,6 +6000,7 @@ class UnitSerializationRoots : public SerializationRoots {
|
||||
ASSERT(deferred_object->IsCode());
|
||||
CodePtr code = static_cast<CodePtr>(deferred_object->ptr());
|
||||
ASSERT(s->RefId(code) == (start_index + i));
|
||||
ASSERT(!Code::IsDiscarded(code));
|
||||
s->WriteInstructions(code->untag()->instructions_,
|
||||
code->untag()->unchecked_offset_, code, false);
|
||||
if (!FLAG_use_bare_instructions) {
|
||||
@@ -6030,7 +6056,8 @@ class UnitDeserializationRoots : public DeserializationRoots {
|
||||
deferred_stop_index_ = deferred_start_index_ + d->ReadUnsigned();
|
||||
for (intptr_t id = deferred_start_index_; id < deferred_stop_index_; id++) {
|
||||
CodePtr code = static_cast<CodePtr>(d->Ref(id));
|
||||
d->ReadInstructions(code, false);
|
||||
ASSERT(!Code::IsUnknownDartCode(code));
|
||||
d->ReadInstructions(code, /*deferred=*/false, /*discarded=*/false);
|
||||
if (code->untag()->owner_->IsHeapObject() &&
|
||||
code->untag()->owner_->IsFunction()) {
|
||||
FunctionPtr func = static_cast<FunctionPtr>(code->untag()->owner_);
|
||||
@@ -6070,12 +6097,13 @@ class UnitDeserializationRoots : public DeserializationRoots {
|
||||
if (isolate_group->dispatch_table_snapshot() != nullptr) {
|
||||
ReadStream stream(isolate_group->dispatch_table_snapshot(),
|
||||
isolate_group->dispatch_table_snapshot_size());
|
||||
d->ReadDispatchTable(&stream);
|
||||
d->ReadDispatchTable(&stream, /*deferred=*/true, deferred_start_index_,
|
||||
deferred_stop_index_);
|
||||
}
|
||||
}
|
||||
|
||||
void PostLoad(Deserializer* d, const Array& refs) {
|
||||
d->EndInstructions(refs, deferred_start_index_, deferred_stop_index_);
|
||||
d->EndInstructions();
|
||||
unit_.set_base_objects(refs);
|
||||
}
|
||||
|
||||
@@ -6523,8 +6551,8 @@ bool Serializer::InCurrentLoadingUnit(ObjectPtr obj, bool record) {
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
void Serializer::PrepareInstructions() {
|
||||
if (!Snapshot::IncludesCode(kind())) return;
|
||||
intptr_t Serializer::PrepareInstructions() {
|
||||
if (!Snapshot::IncludesCode(kind())) return 0;
|
||||
|
||||
CodeSerializationCluster* cluster =
|
||||
static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid]);
|
||||
@@ -6576,8 +6604,10 @@ void Serializer::PrepareInstructions() {
|
||||
GrowableArray<ImageWriterCommand> writer_commands;
|
||||
RelocateCodeObjects(vm_, &code_objects, &writer_commands);
|
||||
image_writer_->PrepareForSerialization(&writer_commands);
|
||||
return code_objects.length();
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Serializer::WriteInstructions(InstructionsPtr instr,
|
||||
@@ -6614,6 +6644,16 @@ void Serializer::WriteInstructions(InstructionsPtr instr,
|
||||
(unchecked_offset << 1) | (Code::HasMonomorphicEntry(code) ? 0x1 : 0x0);
|
||||
WriteUnsigned(payload_info);
|
||||
previous_text_offset_ = offset;
|
||||
|
||||
if (Code::IsDiscarded(code)) {
|
||||
// Discarded Code objects are not supported in the vm isolate snapshot.
|
||||
ASSERT(!vm_);
|
||||
// Stack maps of discarded Code objects are written along with
|
||||
// instructions so they can be added to instructions table during
|
||||
// deserialization.
|
||||
WritePropertyRef(code->untag()->compressed_stackmaps_,
|
||||
"compressed_stackmaps_");
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -6828,8 +6868,14 @@ ZoneGrowableArray<Object*>* Serializer::Serialize(SerializationRoots* roots) {
|
||||
}
|
||||
}
|
||||
GrowableArray<SerializationCluster*> clusters;
|
||||
// Code cluster should be deserialized before Function as
|
||||
// FunctionDeserializationCluster::ReadFill uses instructions table
|
||||
// which is filled in CodeDeserializationCluster::ReadFill.
|
||||
if (clusters_by_cid_[kCodeCid] != nullptr) {
|
||||
clusters.Add(clusters_by_cid_[kCodeCid]);
|
||||
}
|
||||
for (intptr_t cid = 0; cid < num_cids_; cid++) {
|
||||
if (clusters_by_cid_[cid] != nullptr) {
|
||||
if (clusters_by_cid_[cid] != nullptr && cid != kCodeCid) {
|
||||
clusters.Add(clusters_by_cid_[cid]);
|
||||
}
|
||||
}
|
||||
@@ -6842,7 +6888,7 @@ ZoneGrowableArray<Object*>* Serializer::Serialize(SerializationRoots* roots) {
|
||||
}
|
||||
#endif
|
||||
|
||||
PrepareInstructions();
|
||||
instructions_table_len_ = PrepareInstructions();
|
||||
|
||||
intptr_t num_objects = num_base_objects_ + num_written_objects_;
|
||||
#if defined(ARCH_IS_64_BIT)
|
||||
@@ -6861,6 +6907,9 @@ ZoneGrowableArray<Object*>* Serializer::Serialize(SerializationRoots* roots) {
|
||||
} else {
|
||||
WriteUnsigned(0);
|
||||
}
|
||||
ASSERT((instructions_table_len_ == 0) ||
|
||||
(FLAG_precompiled_mode && FLAG_use_bare_instructions));
|
||||
WriteUnsigned(instructions_table_len_);
|
||||
|
||||
for (SerializationCluster* cluster : canonical_clusters) {
|
||||
cluster->WriteAndMeasureAlloc(this);
|
||||
@@ -7121,6 +7170,14 @@ void Serializer::PrintSnapshotSizes() {
|
||||
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
|
||||
"DispatchTable", entry_count, dispatch_table_size_));
|
||||
}
|
||||
if (instructions_table_len_ > 0) {
|
||||
const intptr_t memory_size =
|
||||
compiler::target::InstructionsTable::InstanceSize(
|
||||
instructions_table_len_) +
|
||||
compiler::target::Array::InstanceSize(instructions_table_len_);
|
||||
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
|
||||
"InstructionsTable", instructions_table_len_, 0, memory_size));
|
||||
}
|
||||
clusters_by_size.Sort(CompareClusters);
|
||||
double total_size =
|
||||
static_cast<double>(bytes_written() + GetDataSize() + text_size);
|
||||
@@ -7158,7 +7215,8 @@ Deserializer::Deserializer(Thread* thread,
|
||||
canonical_clusters_(nullptr),
|
||||
clusters_(nullptr),
|
||||
initial_field_table_(thread->isolate_group()->initial_field_table()),
|
||||
is_non_root_unit_(is_non_root_unit) {
|
||||
is_non_root_unit_(is_non_root_unit),
|
||||
instructions_table_(InstructionsTable::Handle(thread->zone())) {
|
||||
if (Snapshot::IncludesCode(kind)) {
|
||||
ASSERT(instructions_buffer != nullptr);
|
||||
ASSERT(data_buffer != nullptr);
|
||||
@@ -7308,7 +7366,10 @@ DeserializationCluster* Deserializer::ReadCluster() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Deserializer::ReadDispatchTable(ReadStream* stream) {
|
||||
void Deserializer::ReadDispatchTable(ReadStream* stream,
|
||||
bool deferred,
|
||||
intptr_t deferred_code_start_index,
|
||||
intptr_t deferred_code_end_index) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
const uint8_t* table_snapshot_start = stream->AddressOfCurrentPosition();
|
||||
const intptr_t length = stream->ReadUnsigned();
|
||||
@@ -7323,8 +7384,16 @@ void Deserializer::ReadDispatchTable(ReadStream* stream) {
|
||||
auto code = IG->object_store()->dispatch_table_null_error_stub();
|
||||
ASSERT(code != Code::null());
|
||||
uword null_entry = Code::EntryPointOf(code);
|
||||
uword not_loaded_entry = StubCode::NotLoaded().EntryPoint();
|
||||
|
||||
auto const table = new DispatchTable(length);
|
||||
DispatchTable* table;
|
||||
if (deferred) {
|
||||
table = IG->dispatch_table();
|
||||
ASSERT(table != nullptr && table->length() == length);
|
||||
} else {
|
||||
ASSERT(IG->dispatch_table() == nullptr);
|
||||
table = new DispatchTable(length);
|
||||
}
|
||||
auto const array = table->array();
|
||||
uword value = 0;
|
||||
uword recent[kDispatchTableRecentCount] = {0};
|
||||
@@ -7347,8 +7416,24 @@ void Deserializer::ReadDispatchTable(ReadStream* stream) {
|
||||
repeat_count = encoded - 1;
|
||||
} else {
|
||||
intptr_t cluster_index = encoded - kDispatchTableIndexBase;
|
||||
code = Code::RawCast(Ref(first_code_id + cluster_index));
|
||||
value = Code::EntryPointOf(code);
|
||||
if (deferred) {
|
||||
intptr_t id = first_code_id + cluster_index;
|
||||
if ((deferred_code_start_index <= id) &&
|
||||
(id < deferred_code_end_index)) {
|
||||
// Deferred instructions are at the end of the instructions table.
|
||||
value = instructions_table().EntryPointAt(
|
||||
instructions_table().length() - deferred_code_end_index + id);
|
||||
} else {
|
||||
// Reuse old value from the dispatch table.
|
||||
value = array[i];
|
||||
}
|
||||
} else {
|
||||
if (cluster_index < instructions_table().length()) {
|
||||
value = instructions_table().EntryPointAt(cluster_index);
|
||||
} else {
|
||||
value = not_loaded_entry;
|
||||
}
|
||||
}
|
||||
recent[recent_index] = value;
|
||||
recent_index = (recent_index + 1) & kDispatchTableRecentMask;
|
||||
}
|
||||
@@ -7356,11 +7441,13 @@ void Deserializer::ReadDispatchTable(ReadStream* stream) {
|
||||
}
|
||||
ASSERT(repeat_count == 0);
|
||||
|
||||
IG->set_dispatch_table(table);
|
||||
intptr_t table_snapshot_size =
|
||||
stream->AddressOfCurrentPosition() - table_snapshot_start;
|
||||
IG->set_dispatch_table_snapshot(table_snapshot_start);
|
||||
IG->set_dispatch_table_snapshot_size(table_snapshot_size);
|
||||
if (!deferred) {
|
||||
IG->set_dispatch_table(table);
|
||||
intptr_t table_snapshot_size =
|
||||
stream->AddressOfCurrentPosition() - table_snapshot_start;
|
||||
IG->set_dispatch_table_snapshot(table_snapshot_start);
|
||||
IG->set_dispatch_table_snapshot_size(table_snapshot_size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -7481,8 +7568,11 @@ ApiErrorPtr FullSnapshotReader::ConvertToApiError(char* message) {
|
||||
return ApiError::New(msg, Heap::kOld);
|
||||
}
|
||||
|
||||
void Deserializer::ReadInstructions(CodePtr code, bool deferred) {
|
||||
void Deserializer::ReadInstructions(CodePtr code,
|
||||
bool deferred,
|
||||
bool discarded) {
|
||||
if (deferred) {
|
||||
ASSERT(!discarded);
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (FLAG_use_bare_instructions) {
|
||||
uword entry_point = StubCode::NotLoaded().EntryPoint();
|
||||
@@ -7508,8 +7598,6 @@ void Deserializer::ReadInstructions(CodePtr code, bool deferred) {
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (FLAG_use_bare_instructions) {
|
||||
// There are no serialized RawInstructions objects in this mode.
|
||||
code->untag()->instructions_ = Instructions::null();
|
||||
previous_text_offset_ += ReadUnsigned();
|
||||
const uword payload_start =
|
||||
image_reader_->GetBareInstructionsAt(previous_text_offset_);
|
||||
@@ -7528,11 +7616,23 @@ void Deserializer::ReadInstructions(CodePtr code, bool deferred) {
|
||||
const uword monomorphic_entry_point =
|
||||
payload_start + monomorphic_entry_offset;
|
||||
|
||||
code->untag()->entry_point_ = entry_point;
|
||||
code->untag()->unchecked_entry_point_ = entry_point + unchecked_offset;
|
||||
code->untag()->monomorphic_entry_point_ = monomorphic_entry_point;
|
||||
code->untag()->monomorphic_unchecked_entry_point_ =
|
||||
monomorphic_entry_point + unchecked_offset;
|
||||
ObjectPtr code_descriptor = code;
|
||||
if (discarded) {
|
||||
code_descriptor = static_cast<CompressedStackMapsPtr>(ReadRef());
|
||||
}
|
||||
|
||||
instructions_table_.SetEntryAt(instructions_index_++, payload_start,
|
||||
has_monomorphic_entrypoint, code_descriptor);
|
||||
|
||||
if (!discarded) {
|
||||
// There are no serialized RawInstructions objects in this mode.
|
||||
code->untag()->instructions_ = Instructions::null();
|
||||
code->untag()->entry_point_ = entry_point;
|
||||
code->untag()->unchecked_entry_point_ = entry_point + unchecked_offset;
|
||||
code->untag()->monomorphic_entry_point_ = monomorphic_entry_point;
|
||||
code->untag()->monomorphic_unchecked_entry_point_ =
|
||||
monomorphic_entry_point + unchecked_offset;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -7554,38 +7654,32 @@ void Deserializer::ReadInstructions(CodePtr code, bool deferred) {
|
||||
Code::InitializeCachedEntryPointsFrom(code, instr, unchecked_offset);
|
||||
}
|
||||
|
||||
void Deserializer::EndInstructions(const Array& refs,
|
||||
intptr_t start_index,
|
||||
intptr_t stop_index) {
|
||||
void Deserializer::EndInstructions() {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (FLAG_use_bare_instructions) {
|
||||
uword previous_end = image_reader_->GetBareInstructionsEnd();
|
||||
for (intptr_t id = stop_index - 1; id >= start_index; id--) {
|
||||
CodePtr code = static_cast<CodePtr>(refs.At(id));
|
||||
uword start = Code::PayloadStartOf(code);
|
||||
for (intptr_t i = instructions_index_ - 1; i >= 0; --i) {
|
||||
ObjectPtr descriptor = instructions_table_.DescriptorAt(i);
|
||||
uword start = instructions_table_.PayloadStartAt(i);
|
||||
ASSERT(start <= previous_end);
|
||||
code->untag()->instructions_length_ = previous_end - start;
|
||||
if (descriptor->IsCode()) {
|
||||
CodePtr code = static_cast<CodePtr>(descriptor);
|
||||
code->untag()->instructions_length_ = previous_end - start;
|
||||
}
|
||||
previous_end = start;
|
||||
}
|
||||
|
||||
// Build an array of code objects representing the order in which the
|
||||
// [Code]'s instructions will be located in memory.
|
||||
const intptr_t count = stop_index - start_index;
|
||||
const Array& order_table =
|
||||
Array::Handle(zone_, Array::New(count, Heap::kOld));
|
||||
Object& code = Object::Handle(zone_);
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
code = refs.At(start_index + i);
|
||||
order_table.SetAt(i, code);
|
||||
}
|
||||
ObjectStore* object_store = IsolateGroup::Current()->object_store();
|
||||
GrowableObjectArray& order_tables =
|
||||
GrowableObjectArray::Handle(zone_, object_store->code_order_tables());
|
||||
if (order_tables.IsNull()) {
|
||||
order_tables = GrowableObjectArray::New(Heap::kOld);
|
||||
object_store->set_code_order_tables(order_tables);
|
||||
GrowableObjectArray& tables =
|
||||
GrowableObjectArray::Handle(zone_, object_store->instructions_tables());
|
||||
if (tables.IsNull()) {
|
||||
tables = GrowableObjectArray::New(Heap::kOld);
|
||||
object_store->set_instructions_tables(tables);
|
||||
}
|
||||
if ((tables.Length() == 0) ||
|
||||
(tables.At(tables.Length() - 1) != instructions_table_.ptr())) {
|
||||
tables.Add(instructions_table_, Heap::kOld);
|
||||
}
|
||||
order_tables.Add(order_table, Heap::kOld);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -7616,6 +7710,7 @@ void Deserializer::Deserialize(DeserializationRoots* roots) {
|
||||
num_canonical_clusters_ = ReadUnsigned();
|
||||
num_clusters_ = ReadUnsigned();
|
||||
const intptr_t initial_field_table_len = ReadUnsigned();
|
||||
const intptr_t instructions_table_len = ReadUnsigned();
|
||||
|
||||
canonical_clusters_ = new DeserializationCluster*[num_canonical_clusters_];
|
||||
clusters_ = new DeserializationCluster*[num_clusters_];
|
||||
@@ -7625,6 +7720,18 @@ void Deserializer::Deserialize(DeserializationRoots* roots) {
|
||||
ASSERT_EQUAL(initial_field_table_->NumFieldIds(), initial_field_table_len);
|
||||
}
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (instructions_table_len > 0) {
|
||||
ASSERT(FLAG_precompiled_mode && FLAG_use_bare_instructions);
|
||||
const uword start_pc = image_reader_->GetBareInstructionsAt(0);
|
||||
const uword end_pc = image_reader_->GetBareInstructionsEnd();
|
||||
instructions_table_ =
|
||||
InstructionsTable::New(instructions_table_len, start_pc, end_pc);
|
||||
}
|
||||
#else
|
||||
ASSERT(instructions_table_len == 0);
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
bool primary;
|
||||
{
|
||||
// The deserializer initializes objects without using the write barrier,
|
||||
|
||||
@@ -373,7 +373,10 @@ class Serializer : public ThreadStackResource {
|
||||
Write<int32_t>(cid);
|
||||
}
|
||||
|
||||
void PrepareInstructions();
|
||||
// Sorts Code objects and reorders instructions before writing snapshot.
|
||||
// Returns length of instructions table (in bare instructions mode).
|
||||
intptr_t PrepareInstructions();
|
||||
|
||||
void WriteInstructions(InstructionsPtr instr,
|
||||
uint32_t unchecked_offset,
|
||||
CodePtr code,
|
||||
@@ -460,6 +463,7 @@ class Serializer : public ThreadStackResource {
|
||||
|
||||
intptr_t dispatch_table_size_ = 0;
|
||||
intptr_t bytes_heap_allocated_ = 0;
|
||||
intptr_t instructions_table_len_ = 0;
|
||||
|
||||
// True if writing VM snapshot, false for Isolate snapshot.
|
||||
bool vm_;
|
||||
@@ -652,18 +656,21 @@ class Deserializer : public ThreadStackResource {
|
||||
return Read<int32_t>();
|
||||
}
|
||||
|
||||
void ReadInstructions(CodePtr code, bool deferred);
|
||||
void EndInstructions(const Array& refs,
|
||||
intptr_t start_index,
|
||||
intptr_t stop_index);
|
||||
void ReadInstructions(CodePtr code, bool deferred, bool discarded);
|
||||
void EndInstructions();
|
||||
ObjectPtr GetObjectAt(uint32_t offset) const;
|
||||
|
||||
void Deserialize(DeserializationRoots* roots);
|
||||
|
||||
DeserializationCluster* ReadCluster();
|
||||
|
||||
void ReadDispatchTable() { ReadDispatchTable(&stream_); }
|
||||
void ReadDispatchTable(ReadStream* stream);
|
||||
void ReadDispatchTable() {
|
||||
ReadDispatchTable(&stream_, /*deferred=*/false, -1, -1);
|
||||
}
|
||||
void ReadDispatchTable(ReadStream* stream,
|
||||
bool deferred,
|
||||
intptr_t deferred_code_start_index,
|
||||
intptr_t deferred_code_end_index);
|
||||
|
||||
intptr_t next_index() const { return next_ref_index_; }
|
||||
Heap* heap() const { return heap_; }
|
||||
@@ -671,6 +678,11 @@ class Deserializer : public ThreadStackResource {
|
||||
Snapshot::Kind kind() const { return kind_; }
|
||||
FieldTable* initial_field_table() const { return initial_field_table_; }
|
||||
bool is_non_root_unit() const { return is_non_root_unit_; }
|
||||
void set_code_start_index(intptr_t value) { code_start_index_ = value; }
|
||||
intptr_t code_start_index() { return code_start_index_; }
|
||||
const InstructionsTable& instructions_table() const {
|
||||
return instructions_table_;
|
||||
}
|
||||
|
||||
private:
|
||||
Heap* heap_;
|
||||
@@ -685,10 +697,13 @@ class Deserializer : public ThreadStackResource {
|
||||
ArrayPtr refs_;
|
||||
intptr_t next_ref_index_;
|
||||
intptr_t previous_text_offset_;
|
||||
intptr_t code_start_index_ = 0;
|
||||
intptr_t instructions_index_ = 0;
|
||||
DeserializationCluster** canonical_clusters_;
|
||||
DeserializationCluster** clusters_;
|
||||
FieldTable* initial_field_table_;
|
||||
const bool is_non_root_unit_;
|
||||
InstructionsTable& instructions_table_;
|
||||
};
|
||||
|
||||
#define ReadFromTo(obj, ...) d->ReadFromTo(obj, ##__VA_ARGS__);
|
||||
|
||||
@@ -1581,6 +1581,7 @@ void Precompiler::CheckForNewDynamicFunctions() {
|
||||
Function::CreateDynamicInvocationForwarderName(selector);
|
||||
function2 = function.GetDynamicInvocationForwarder(selector2);
|
||||
AddFunction(function2, RetainReasons::kDynamicInvocationForwarder);
|
||||
functions_called_dynamically_.Insert(function2);
|
||||
}
|
||||
} else if (function.kind() == UntaggedFunction::kRegularFunction) {
|
||||
selector2 = Field::LookupGetterSymbol(selector);
|
||||
@@ -1630,12 +1631,14 @@ void Precompiler::CheckForNewDynamicFunctions() {
|
||||
function2 = function.GetDynamicInvocationForwarder(selector2);
|
||||
AddFunction(function2,
|
||||
RetainReasons::kDynamicInvocationForwarder);
|
||||
functions_called_dynamically_.Insert(function2);
|
||||
}
|
||||
} else {
|
||||
if (metadata.method_or_setter_called_dynamically) {
|
||||
function2 = function.GetDynamicInvocationForwarder(selector2);
|
||||
AddFunction(function2,
|
||||
RetainReasons::kDynamicInvocationForwarder);
|
||||
functions_called_dynamically_.Insert(function2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2671,6 +2674,9 @@ void Precompiler::DropLibraries() {
|
||||
|
||||
// Traverse program structure and mark Code objects
|
||||
// which do not have useful information as discarded.
|
||||
// Should be called after Precompiler::ReplaceFunctionStaticCallEntries().
|
||||
// Should be called before ProgramVisitor::Dedup() as Dedup may clear
|
||||
// static calls target table.
|
||||
void Precompiler::DiscardCodeObjects() {
|
||||
class DiscardCodeVisitor : public CodeVisitor {
|
||||
public:
|
||||
@@ -2680,15 +2686,45 @@ void Precompiler::DiscardCodeObjects() {
|
||||
const FunctionSet& functions_called_dynamically)
|
||||
: zone_(zone),
|
||||
function_(Function::Handle(zone)),
|
||||
class_(Class::Handle(zone)),
|
||||
library_(Library::Handle(zone)),
|
||||
loading_unit_(LoadingUnit::Handle(zone)),
|
||||
static_calls_target_table_(Array::Handle(zone)),
|
||||
kind_and_offset_(Smi::Handle(zone)),
|
||||
call_target_(Code::Handle(zone)),
|
||||
targets_of_calls_via_code_(
|
||||
GrowableObjectArray::Handle(zone, GrowableObjectArray::New())),
|
||||
functions_to_retain_(functions_to_retain),
|
||||
entry_point_functions_(entry_point_functions),
|
||||
functions_called_dynamically_(functions_called_dynamically) {}
|
||||
|
||||
// Certain static calls (e.g. between different loading units) are
|
||||
// performed through Code objects indirectly. Such Code objects
|
||||
// cannot be fully discarded.
|
||||
void RecordCodeObjectsUsedForCalls(const Code& code) {
|
||||
static_calls_target_table_ = code.static_calls_target_table();
|
||||
if (static_calls_target_table_.IsNull()) return;
|
||||
|
||||
StaticCallsTable static_calls(static_calls_target_table_);
|
||||
for (const auto& view : static_calls) {
|
||||
kind_and_offset_ = view.Get<Code::kSCallTableKindAndOffset>();
|
||||
auto const kind = Code::KindField::decode(kind_and_offset_.Value());
|
||||
if (kind == Code::kCallViaCode) {
|
||||
call_target_ =
|
||||
Code::RawCast(view.Get<Code::kSCallTableCodeOrTypeTarget>());
|
||||
ASSERT(!call_target_.IsNull());
|
||||
targets_of_calls_via_code_.Add(call_target_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VisitCode(const Code& code) override {
|
||||
++total_code_objects_;
|
||||
|
||||
RecordCodeObjectsUsedForCalls(code);
|
||||
|
||||
// Only discard Code objects corresponding to Dart functions.
|
||||
if (!code.IsFunctionCode()) {
|
||||
if (!code.IsFunctionCode() || code.IsUnknownDartCode()) {
|
||||
++non_function_codes_;
|
||||
return;
|
||||
}
|
||||
@@ -2740,10 +2776,39 @@ void Precompiler::DiscardCodeObjects() {
|
||||
ASSERT(!functions_called_dynamically_.ContainsKey(function_));
|
||||
}
|
||||
|
||||
// Retain Code objects in the non-root loading unit as
|
||||
// they are allocated while loading root unit but filled
|
||||
// while loading another unit.
|
||||
class_ = function_.Owner();
|
||||
library_ = class_.library();
|
||||
loading_unit_ = library_.loading_unit();
|
||||
if (loading_unit_.id() != LoadingUnit::kRootId) {
|
||||
++codes_with_deferred_function_;
|
||||
return;
|
||||
}
|
||||
|
||||
// Retain Code objects corresponding to FFI trampolines.
|
||||
if (function_.IsFfiTrampoline()) {
|
||||
++codes_with_ffi_trampoline_function_;
|
||||
return;
|
||||
}
|
||||
|
||||
code.set_is_discarded(true);
|
||||
++discarded_codes_;
|
||||
}
|
||||
|
||||
void RetainCodeObjectsUsedAsCallTargets() {
|
||||
for (intptr_t i = 0, n = targets_of_calls_via_code_.Length(); i < n;
|
||||
++i) {
|
||||
call_target_ = Code::RawCast(targets_of_calls_via_code_.At(i));
|
||||
if (call_target_.is_discarded()) {
|
||||
call_target_.set_is_discarded(false);
|
||||
++codes_used_as_call_targets_;
|
||||
--discarded_codes_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintStatistics() const {
|
||||
THR_Print("Discarding Code objects:\n");
|
||||
THR_Print(" %8" Pd " non-function Codes\n", non_function_codes_);
|
||||
@@ -2757,10 +2822,16 @@ void Precompiler::DiscardCodeObjects() {
|
||||
codes_with_native_function_);
|
||||
THR_Print(" %8" Pd " Codes with async closure functions\n",
|
||||
codes_with_async_closure_function_);
|
||||
THR_Print(" %8" Pd " Codes with dynamically called functions\n",
|
||||
codes_with_dynamically_called_function_);
|
||||
THR_Print(" %8" Pd " Codes with entry point functions\n",
|
||||
codes_with_entry_point_function_);
|
||||
THR_Print(" %8" Pd " Codes with dynamically called functions\n",
|
||||
codes_with_dynamically_called_function_);
|
||||
THR_Print(" %8" Pd " Codes with deferred functions\n",
|
||||
codes_with_deferred_function_);
|
||||
THR_Print(" %8" Pd " Codes with ffi trampoline functions\n",
|
||||
codes_with_ffi_trampoline_function_);
|
||||
THR_Print(" %8" Pd " Codes used as call targets\n",
|
||||
codes_used_as_call_targets_);
|
||||
THR_Print(" %8" Pd " Codes discarded\n", discarded_codes_);
|
||||
THR_Print(" %8" Pd " Codes total\n", total_code_objects_);
|
||||
}
|
||||
@@ -2768,6 +2839,13 @@ void Precompiler::DiscardCodeObjects() {
|
||||
private:
|
||||
Zone* zone_;
|
||||
Function& function_;
|
||||
Class& class_;
|
||||
Library& library_;
|
||||
LoadingUnit& loading_unit_;
|
||||
Array& static_calls_target_table_;
|
||||
Smi& kind_and_offset_;
|
||||
Code& call_target_;
|
||||
GrowableObjectArray& targets_of_calls_via_code_;
|
||||
const FunctionSet& functions_to_retain_;
|
||||
const FunctionSet& entry_point_functions_;
|
||||
const FunctionSet& functions_called_dynamically_;
|
||||
@@ -2780,8 +2858,11 @@ void Precompiler::DiscardCodeObjects() {
|
||||
intptr_t codes_with_invisible_function_ = 0;
|
||||
intptr_t codes_with_native_function_ = 0;
|
||||
intptr_t codes_with_async_closure_function_ = 0;
|
||||
intptr_t codes_with_dynamically_called_function_ = 0;
|
||||
intptr_t codes_with_entry_point_function_ = 0;
|
||||
intptr_t codes_with_dynamically_called_function_ = 0;
|
||||
intptr_t codes_with_deferred_function_ = 0;
|
||||
intptr_t codes_with_ffi_trampoline_function_ = 0;
|
||||
intptr_t codes_used_as_call_targets_ = 0;
|
||||
intptr_t discarded_codes_ = 0;
|
||||
};
|
||||
|
||||
@@ -2796,6 +2877,7 @@ void Precompiler::DiscardCodeObjects() {
|
||||
DiscardCodeVisitor visitor(Z, functions_to_retain_, entry_point_functions_,
|
||||
functions_called_dynamically_);
|
||||
ProgramVisitor::WalkProgram(Z, IG, &visitor);
|
||||
visitor.RetainCodeObjectsUsedAsCallTargets();
|
||||
|
||||
if (FLAG_trace_precompiler) {
|
||||
visitor.PrintStatistics();
|
||||
|
||||
@@ -1151,6 +1151,16 @@ word InstructionsSection::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word InstructionsTable::InstanceSize(intptr_t length) {
|
||||
return RoundedAllocationSize(InstructionsTable::InstanceSize() +
|
||||
length *
|
||||
dart::InstructionsTable::kBytesPerElement);
|
||||
}
|
||||
|
||||
word InstructionsTable::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Instructions::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
@@ -1193,6 +1193,13 @@ class InstructionsSection : public AllStatic {
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class InstructionsTable : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize(intptr_t length);
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Instructions : public AllStatic {
|
||||
public:
|
||||
static const word kMonomorphicEntryOffsetJIT;
|
||||
|
||||
@@ -493,6 +493,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
8;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 20;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
20;
|
||||
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 =
|
||||
@@ -1033,6 +1035,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
40;
|
||||
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 =
|
||||
@@ -1563,6 +1567,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
8;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 20;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
20;
|
||||
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 =
|
||||
@@ -2104,6 +2110,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
40;
|
||||
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 =
|
||||
@@ -2643,6 +2651,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
40;
|
||||
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 =
|
||||
@@ -3183,6 +3193,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
40;
|
||||
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 =
|
||||
@@ -3712,6 +3724,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
8;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 20;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
20;
|
||||
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 =
|
||||
@@ -4246,6 +4260,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
40;
|
||||
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 =
|
||||
@@ -4770,6 +4786,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
8;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 20;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
20;
|
||||
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 =
|
||||
@@ -5305,6 +5323,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
40;
|
||||
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 =
|
||||
@@ -5838,6 +5858,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
40;
|
||||
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 =
|
||||
@@ -6372,6 +6394,8 @@ static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
|
||||
16;
|
||||
static constexpr dart::compiler::target::word
|
||||
InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word InstructionsTable_InstanceSize =
|
||||
40;
|
||||
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 =
|
||||
@@ -6957,6 +6981,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 8;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 20;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 20;
|
||||
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
|
||||
@@ -7555,6 +7581,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 40;
|
||||
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
|
||||
@@ -8157,6 +8185,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 40;
|
||||
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
|
||||
@@ -8755,6 +8785,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 40;
|
||||
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
|
||||
@@ -9354,6 +9386,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 40;
|
||||
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
|
||||
@@ -9943,6 +9977,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 8;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 20;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 20;
|
||||
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
|
||||
@@ -10534,6 +10570,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 40;
|
||||
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
|
||||
@@ -11129,6 +11167,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 40;
|
||||
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
|
||||
@@ -11720,6 +11760,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 40;
|
||||
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
|
||||
@@ -12312,6 +12354,8 @@ static constexpr dart::compiler::target::word
|
||||
AOT_Instructions_UnalignedHeaderSize = 16;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsSection_UnalignedHeaderSize = 40;
|
||||
static constexpr dart::compiler::target::word
|
||||
AOT_InstructionsTable_InstanceSize = 40;
|
||||
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
|
||||
|
||||
@@ -340,6 +340,7 @@
|
||||
SIZEOF(Instructions, UnalignedHeaderSize, UntaggedInstructions) \
|
||||
SIZEOF(InstructionsSection, UnalignedHeaderSize, \
|
||||
UntaggedInstructionsSection) \
|
||||
SIZEOF(InstructionsTable, InstanceSize, UntaggedInstructionsTable) \
|
||||
SIZEOF(Int32x4, InstanceSize, UntaggedInt32x4) \
|
||||
SIZEOF(Integer, InstanceSize, UntaggedInteger) \
|
||||
SIZEOF(KernelProgramInfo, InstanceSize, UntaggedKernelProgramInfo) \
|
||||
|
||||
@@ -888,9 +888,17 @@ void StubCodeCompiler::GenerateAsynchronousGapMarkerStub(Assembler* assembler) {
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateUnknownDartCodeStub(Assembler* assembler) {
|
||||
// Enter frame to include caller into the backtrace.
|
||||
__ EnterStubFrame();
|
||||
__ Breakpoint(); // Marker stub.
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateNotLoadedStub(Assembler* assembler) {
|
||||
__ EnterStubFrame();
|
||||
__ CallRuntime(kNotLoadedRuntimeEntry, 0);
|
||||
__ Breakpoint();
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -1168,7 +1168,7 @@ void StubCodeCompiler::GenerateAllocateMintSharedWithoutFPURegsStub(
|
||||
// Called when invoking Dart code from C++ (VM code).
|
||||
// Input parameters:
|
||||
// LR : points to return address.
|
||||
// R0 : code object of the Dart function to call.
|
||||
// R0 : target code or entry point (in bare instructions mode).
|
||||
// R1 : arguments descriptor array.
|
||||
// R2 : arguments array.
|
||||
// R3 : current thread.
|
||||
@@ -1260,11 +1260,12 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
// Call the Dart code entrypoint.
|
||||
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
|
||||
__ SetupGlobalPoolAndDispatchTable();
|
||||
__ LoadImmediate(CODE_REG, 0); // GC safe value into CODE_REG.
|
||||
} else {
|
||||
__ LoadImmediate(PP, 0); // GC safe value into PP.
|
||||
__ ldr(CODE_REG, Address(R0, target::VMHandles::kOffsetOfRawPtrInHandle));
|
||||
__ ldr(R0, FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
}
|
||||
__ ldr(CODE_REG, Address(R0, target::VMHandles::kOffsetOfRawPtrInHandle));
|
||||
__ ldr(R0, FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
__ blx(R0); // R4 is the arguments descriptor array.
|
||||
|
||||
// Get rid of arguments pushed on the stack.
|
||||
@@ -3290,12 +3291,6 @@ void StubCodeCompiler::GenerateSingleTargetCallStub(Assembler* assembler) {
|
||||
CODE_REG, target::Code::entry_point_offset(CodeEntryKind::kMonomorphic)));
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateNotLoadedStub(Assembler* assembler) {
|
||||
__ EnterStubFrame();
|
||||
__ CallRuntime(kNotLoadedRuntimeEntry, 0);
|
||||
__ bkpt(0);
|
||||
}
|
||||
|
||||
// Instantiate type arguments from instantiator and function type args.
|
||||
// R3 uninstantiated type arguments.
|
||||
// R2 instantiator type arguments.
|
||||
|
||||
@@ -1304,7 +1304,7 @@ void StubCodeCompiler::GenerateAllocateMintSharedWithoutFPURegsStub(
|
||||
// Called when invoking Dart code from C++ (VM code).
|
||||
// Input parameters:
|
||||
// LR : points to return address.
|
||||
// R0 : code object of the Dart function to call.
|
||||
// R0 : target code or entry point (in bare instructions mode).
|
||||
// R1 : arguments descriptor array.
|
||||
// R2 : arguments array.
|
||||
// R3 : current thread.
|
||||
@@ -1404,16 +1404,17 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
|
||||
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
|
||||
__ SetupGlobalPoolAndDispatchTable();
|
||||
__ mov(CODE_REG, ZR); // GC-safe value into CODE_REG.
|
||||
} else {
|
||||
// We now load the pool pointer(PP) with a GC safe value as we are about to
|
||||
// invoke dart code. We don't need a real object pool here.
|
||||
// Smi zero does not work because ARM64 assumes PP to be untagged.
|
||||
__ LoadObject(PP, NullObject());
|
||||
__ ldr(CODE_REG, Address(R0, VMHandles::kOffsetOfRawPtrInHandle));
|
||||
__ ldr(R0, FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
}
|
||||
|
||||
// Call the Dart code entrypoint.
|
||||
__ ldr(CODE_REG, Address(R0, VMHandles::kOffsetOfRawPtrInHandle));
|
||||
__ ldr(R0, FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
__ blr(R0); // R4 is the arguments descriptor array.
|
||||
__ Comment("InvokeDartCodeStub return");
|
||||
|
||||
@@ -3450,12 +3451,6 @@ void StubCodeCompiler::GenerateSingleTargetCallStub(Assembler* assembler) {
|
||||
__ br(R1);
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateNotLoadedStub(Assembler* assembler) {
|
||||
__ EnterStubFrame();
|
||||
__ CallRuntime(kNotLoadedRuntimeEntry, 0);
|
||||
__ brk(0);
|
||||
}
|
||||
|
||||
// Instantiate type arguments from instantiator and function type args.
|
||||
// R3 uninstantiated type arguments.
|
||||
// R2 instantiator type arguments.
|
||||
|
||||
@@ -2784,12 +2784,6 @@ void StubCodeCompiler::GenerateSingleTargetCallStub(Assembler* assembler) {
|
||||
__ int3(); // AOT only.
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateNotLoadedStub(Assembler* assembler) {
|
||||
__ EnterStubFrame();
|
||||
__ CallRuntime(kNotLoadedRuntimeEntry, 0);
|
||||
__ int3();
|
||||
}
|
||||
|
||||
// Instantiate type arguments from instantiator and function type args.
|
||||
// EBX: uninstantiated type arguments.
|
||||
// EDX: instantiator type arguments.
|
||||
|
||||
@@ -1231,7 +1231,7 @@ static const RegisterSet kCalleeSavedRegisterSet(
|
||||
// Called when invoking Dart code from C++ (VM code).
|
||||
// Input parameters:
|
||||
// RSP : points to return address.
|
||||
// RDI : target code
|
||||
// RDI : target code or entry point (in bare instructions mode).
|
||||
// RSI : arguments descriptor array.
|
||||
// RDX : arguments array.
|
||||
// RCX : current thread.
|
||||
@@ -1239,7 +1239,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
__ pushq(Address(RSP, 0)); // Marker for the profiler.
|
||||
__ EnterFrame(0);
|
||||
|
||||
const Register kTargetCodeReg = CallingConventions::kArg1Reg;
|
||||
const Register kTargetReg = CallingConventions::kArg1Reg;
|
||||
const Register kArgDescReg = CallingConventions::kArg2Reg;
|
||||
const Register kArgsReg = CallingConventions::kArg3Reg;
|
||||
const Register kThreadReg = CallingConventions::kArg4Reg;
|
||||
@@ -1304,8 +1304,8 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
// Load arguments descriptor array into R10, which is passed to Dart code.
|
||||
__ movq(R10, Address(kArgDescReg, VMHandles::kOffsetOfRawPtrInHandle));
|
||||
|
||||
// Push arguments. At this point we only need to preserve kTargetCodeReg.
|
||||
ASSERT(kTargetCodeReg != RDX);
|
||||
// Push arguments. At this point we only need to preserve kTargetReg.
|
||||
ASSERT(kTargetReg != RDX);
|
||||
|
||||
// Load number of arguments into RBX and adjust count for type arguments.
|
||||
__ movq(RBX, FieldAddress(R10, target::ArgumentsDescriptor::count_offset()));
|
||||
@@ -1339,14 +1339,14 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
// Call the Dart code entrypoint.
|
||||
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
|
||||
__ movq(PP, Address(THR, target::Thread::global_object_pool_offset()));
|
||||
__ xorq(CODE_REG, CODE_REG); // GC-safe value into CODE_REG.
|
||||
} else {
|
||||
__ xorq(PP, PP); // GC-safe value into PP.
|
||||
__ movq(CODE_REG, Address(kTargetReg, VMHandles::kOffsetOfRawPtrInHandle));
|
||||
__ movq(kTargetReg,
|
||||
FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
}
|
||||
__ movq(CODE_REG,
|
||||
Address(kTargetCodeReg, VMHandles::kOffsetOfRawPtrInHandle));
|
||||
__ movq(kTargetCodeReg,
|
||||
FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
__ call(kTargetCodeReg); // R10 is the arguments descriptor array.
|
||||
__ call(kTargetReg); // R10 is the arguments descriptor array.
|
||||
|
||||
// Read the saved number of passed arguments as Smi.
|
||||
__ movq(RDX, Address(RBP, kArgumentsDescOffset));
|
||||
@@ -3380,12 +3380,6 @@ void StubCodeCompiler::GenerateSingleTargetCallStub(Assembler* assembler) {
|
||||
__ jmp(RCX);
|
||||
}
|
||||
|
||||
void StubCodeCompiler::GenerateNotLoadedStub(Assembler* assembler) {
|
||||
__ EnterStubFrame();
|
||||
__ CallRuntime(kNotLoadedRuntimeEntry, 0);
|
||||
__ int3();
|
||||
}
|
||||
|
||||
// Instantiate type arguments from instantiator and function type args.
|
||||
// RBX: uninstantiated type arguments.
|
||||
// RDX: instantiator type arguments.
|
||||
|
||||
@@ -144,7 +144,8 @@ ObjectPtr DartEntry::InvokeFunction(const Function& function,
|
||||
|
||||
// Now Call the invoke stub which will invoke the dart function.
|
||||
const Code& code = Code::Handle(zone, function.CurrentCode());
|
||||
return InvokeCode(code, arguments_descriptor, arguments, thread);
|
||||
return InvokeCode(code, function.entry_point(), arguments_descriptor,
|
||||
arguments, thread);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@@ -155,10 +156,16 @@ typedef uword /*ObjectPtr*/ (*invokestub)(const Code& target_code,
|
||||
const Array& arguments_descriptor,
|
||||
const Array& arguments,
|
||||
Thread* thread);
|
||||
typedef uword /*ObjectPtr*/ (*invokestub_bare_instructions)(
|
||||
uword entry_point,
|
||||
const Array& arguments_descriptor,
|
||||
const Array& arguments,
|
||||
Thread* thread);
|
||||
}
|
||||
|
||||
NO_SANITIZE_SAFE_STACK
|
||||
ObjectPtr DartEntry::InvokeCode(const Code& code,
|
||||
uword entry_point,
|
||||
const Array& arguments_descriptor,
|
||||
const Array& arguments,
|
||||
Thread* thread) {
|
||||
@@ -166,19 +173,27 @@ ObjectPtr DartEntry::InvokeCode(const Code& code,
|
||||
ASSERT(thread->no_callback_scope_depth() == 0);
|
||||
ASSERT(!IsolateGroup::Current()->null_safety_not_set());
|
||||
|
||||
invokestub entrypoint =
|
||||
reinterpret_cast<invokestub>(StubCode::InvokeDartCode().EntryPoint());
|
||||
const uword stub = StubCode::InvokeDartCode().EntryPoint();
|
||||
SuspendLongJumpScope suspend_long_jump_scope(thread);
|
||||
TransitionToGenerated transition(thread);
|
||||
#if defined(USING_SIMULATOR)
|
||||
return bit_copy<ObjectPtr, int64_t>(Simulator::Current()->Call(
|
||||
reinterpret_cast<intptr_t>(entrypoint), reinterpret_cast<intptr_t>(&code),
|
||||
static_cast<intptr_t>(stub),
|
||||
((FLAG_precompiled_mode && FLAG_use_bare_instructions)
|
||||
? static_cast<intptr_t>(entry_point)
|
||||
: reinterpret_cast<intptr_t>(&code)),
|
||||
reinterpret_cast<intptr_t>(&arguments_descriptor),
|
||||
reinterpret_cast<intptr_t>(&arguments),
|
||||
reinterpret_cast<intptr_t>(thread)));
|
||||
#else
|
||||
return static_cast<ObjectPtr>(
|
||||
entrypoint(code, arguments_descriptor, arguments, thread));
|
||||
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
|
||||
return static_cast<ObjectPtr>(
|
||||
(reinterpret_cast<invokestub_bare_instructions>(stub))(
|
||||
entry_point, arguments_descriptor, arguments, thread));
|
||||
} else {
|
||||
return static_cast<ObjectPtr>((reinterpret_cast<invokestub>(stub))(
|
||||
code, arguments_descriptor, arguments, thread));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -194,6 +194,7 @@ class DartEntry : public AllStatic {
|
||||
// Invokes the specified code as if it was a Dart function.
|
||||
// On success, returns an InstancePtr. On failure, an ErrorPtr.
|
||||
static ObjectPtr InvokeCode(const Code& code,
|
||||
uword entry_point,
|
||||
const Array& arguments_descriptor,
|
||||
const Array& arguments,
|
||||
Thread* thread);
|
||||
|
||||
+133
-2
@@ -156,6 +156,7 @@ ClassPtr Object::kernel_program_info_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
ClassPtr Object::code_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
ClassPtr Object::instructions_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
ClassPtr Object::instructions_section_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
ClassPtr Object::instructions_table_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
ClassPtr Object::object_pool_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
ClassPtr Object::pc_descriptors_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
ClassPtr Object::code_source_map_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
@@ -824,6 +825,9 @@ void Object::Init(IsolateGroup* isolate_group) {
|
||||
Class::New<InstructionsSection, RTN::InstructionsSection>(isolate_group);
|
||||
instructions_section_class_ = cls.ptr();
|
||||
|
||||
cls = Class::New<InstructionsTable, RTN::InstructionsTable>(isolate_group);
|
||||
instructions_table_class_ = cls.ptr();
|
||||
|
||||
cls = Class::New<ObjectPool, RTN::ObjectPool>(isolate_group);
|
||||
object_pool_class_ = cls.ptr();
|
||||
|
||||
@@ -1245,6 +1249,7 @@ void Object::Cleanup() {
|
||||
code_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
instructions_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
instructions_section_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
instructions_table_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
object_pool_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
pc_descriptors_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
code_source_map_class_ = static_cast<ClassPtr>(RAW_NULL);
|
||||
@@ -1345,6 +1350,7 @@ void Object::FinalizeVMIsolate(IsolateGroup* isolate_group) {
|
||||
SET_CLASS_NAME(code, Code);
|
||||
SET_CLASS_NAME(instructions, Instructions);
|
||||
SET_CLASS_NAME(instructions_section, InstructionsSection);
|
||||
SET_CLASS_NAME(instructions_table, InstructionsTable);
|
||||
SET_CLASS_NAME(object_pool, ObjectPool);
|
||||
SET_CLASS_NAME(code_source_map, CodeSourceMap);
|
||||
SET_CLASS_NAME(pc_descriptors, PcDescriptors);
|
||||
@@ -4869,6 +4875,8 @@ const char* Class::GenerateUserVisibleName() const {
|
||||
return Symbols::Instructions().ToCString();
|
||||
case kInstructionsSectionCid:
|
||||
return Symbols::InstructionsSection().ToCString();
|
||||
case kInstructionsTableCid:
|
||||
return Symbols::InstructionsTable().ToCString();
|
||||
case kObjectPoolCid:
|
||||
return Symbols::ObjectPool().ToCString();
|
||||
case kCodeSourceMapCid:
|
||||
@@ -9757,7 +9765,10 @@ bool Function::HasDynamicCallers(Zone* zone) const {
|
||||
kernel::ProcedureAttributesMetadata metadata;
|
||||
metadata = kernel::ProcedureAttributesOf(*this, zone);
|
||||
if (IsGetterFunction() || IsImplicitGetterFunction() || IsMethodExtractor()) {
|
||||
return metadata.getter_called_dynamically;
|
||||
// Dynamic method call through field/getter involves dynamic call of
|
||||
// the field/getter.
|
||||
return metadata.getter_called_dynamically ||
|
||||
metadata.method_or_setter_called_dynamically;
|
||||
} else {
|
||||
return metadata.method_or_setter_called_dynamically;
|
||||
}
|
||||
@@ -14149,6 +14160,125 @@ const char* InstructionsSection::ToCString() const {
|
||||
return "InstructionsSection";
|
||||
}
|
||||
|
||||
void InstructionsTable::set_length(intptr_t value) const {
|
||||
StoreNonPointer(&untag()->length_, value);
|
||||
}
|
||||
|
||||
void InstructionsTable::set_start_pc(uword value) const {
|
||||
StoreNonPointer(&untag()->start_pc_, value);
|
||||
}
|
||||
|
||||
void InstructionsTable::set_end_pc(uword value) const {
|
||||
StoreNonPointer(&untag()->end_pc_, value);
|
||||
}
|
||||
|
||||
void InstructionsTable::set_descriptors(const Array& value) const {
|
||||
untag()->set_descriptors(value.ptr());
|
||||
}
|
||||
|
||||
InstructionsTablePtr InstructionsTable::New(intptr_t length,
|
||||
uword start_pc,
|
||||
uword end_pc) {
|
||||
ASSERT(Object::instructions_table_class() != Class::null());
|
||||
ASSERT(length >= 0);
|
||||
ASSERT(start_pc <= end_pc);
|
||||
ASSERT(Utils::IsAligned(start_pc, kPayloadAlignment));
|
||||
Thread* thread = Thread::Current();
|
||||
InstructionsTable& result = InstructionsTable::Handle(thread->zone());
|
||||
{
|
||||
uword size = InstructionsTable::InstanceSize(length);
|
||||
ObjectPtr raw = Object::Allocate(InstructionsTable::kClassId, size,
|
||||
Heap::kOld, /*compressed*/ false);
|
||||
NoSafepointScope no_safepoint;
|
||||
result ^= raw;
|
||||
result.set_length(length);
|
||||
}
|
||||
const Array& descriptors =
|
||||
(length == 0) ? Object::empty_array()
|
||||
: Array::Handle(Array::New(length, Heap::kOld));
|
||||
result.set_descriptors(descriptors);
|
||||
result.set_start_pc(start_pc);
|
||||
result.set_end_pc(end_pc);
|
||||
return result.ptr();
|
||||
}
|
||||
|
||||
void InstructionsTable::SetEntryAt(intptr_t index,
|
||||
uword payload_start,
|
||||
bool has_monomorphic_entrypoint,
|
||||
ObjectPtr descriptor) const {
|
||||
ASSERT((0 <= index) && (index < length()));
|
||||
ASSERT(ContainsPc(payload_start));
|
||||
ASSERT(Utils::IsAligned(payload_start, kPayloadAlignment));
|
||||
|
||||
const uint32_t pc_offset = ConvertPcToOffset(payload_start);
|
||||
ASSERT((index == 0) || (PcOffsetAt(index - 1) <= pc_offset));
|
||||
ASSERT((pc_offset & kHasMonomorphicEntrypointFlag) == 0);
|
||||
|
||||
untag()->data()[index] =
|
||||
pc_offset |
|
||||
(has_monomorphic_entrypoint ? kHasMonomorphicEntrypointFlag : 0);
|
||||
descriptors()->untag()->set_element(index, descriptor);
|
||||
}
|
||||
|
||||
bool InstructionsTable::ContainsPc(InstructionsTablePtr table, uword pc) {
|
||||
return (InstructionsTable::start_pc(table) <= pc) &&
|
||||
(pc < InstructionsTable::end_pc(table));
|
||||
}
|
||||
|
||||
uint32_t InstructionsTable::ConvertPcToOffset(InstructionsTablePtr table,
|
||||
uword pc) {
|
||||
ASSERT(InstructionsTable::ContainsPc(table, pc));
|
||||
const uint32_t pc_offset =
|
||||
static_cast<uint32_t>(pc - InstructionsTable::start_pc(table));
|
||||
ASSERT(InstructionsTable::start_pc(table) + pc_offset == pc); // No overflow.
|
||||
return pc_offset;
|
||||
}
|
||||
|
||||
intptr_t InstructionsTable::FindEntry(InstructionsTablePtr table, uword pc) {
|
||||
// This can run in the middle of GC and must not allocate handles.
|
||||
NoSafepointScope no_safepoint;
|
||||
if (!InstructionsTable::ContainsPc(table, pc)) return -1;
|
||||
const uint32_t pc_offset = InstructionsTable::ConvertPcToOffset(table, pc);
|
||||
intptr_t lo = 0;
|
||||
intptr_t hi = InstructionsTable::length(table) - 1;
|
||||
while (lo <= hi) {
|
||||
intptr_t mid = (hi - lo + 1) / 2 + lo;
|
||||
ASSERT(mid >= lo);
|
||||
ASSERT(mid <= hi);
|
||||
if (pc_offset < InstructionsTable::PcOffsetAt(table, mid)) {
|
||||
hi = mid - 1;
|
||||
} else if ((mid != hi) &&
|
||||
(pc_offset >= InstructionsTable::PcOffsetAt(table, mid + 1))) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ObjectPtr InstructionsTable::DescriptorAt(InstructionsTablePtr table,
|
||||
intptr_t index) {
|
||||
ASSERT((0 <= index) && (index < InstructionsTable::length(table)));
|
||||
return table->untag()->descriptors()->untag()->element(index);
|
||||
}
|
||||
|
||||
uword InstructionsTable::PayloadStartAt(InstructionsTablePtr table,
|
||||
intptr_t index) {
|
||||
return InstructionsTable::start_pc(table) +
|
||||
InstructionsTable::PcOffsetAt(table, index);
|
||||
}
|
||||
|
||||
uword InstructionsTable::EntryPointAt(intptr_t index) const {
|
||||
return PayloadStartAt(index) + (HasMonomorphicEntryPointAt(index)
|
||||
? Instructions::kPolymorphicEntryOffsetAOT
|
||||
: 0);
|
||||
}
|
||||
|
||||
const char* InstructionsTable::ToCString() const {
|
||||
return "InstructionsTable";
|
||||
}
|
||||
|
||||
ObjectPoolPtr ObjectPool::New(intptr_t len) {
|
||||
ASSERT(Object::object_pool_class() != Class::null());
|
||||
if (len < 0 || len > kMaxElements) {
|
||||
@@ -16979,7 +17109,8 @@ bool Code::IsFunctionCode() const {
|
||||
}
|
||||
|
||||
bool Code::IsUnknownDartCode(CodePtr code) {
|
||||
return code == StubCode::UnknownDartCode().ptr();
|
||||
return StubCode::HasBeenInitialized() &&
|
||||
(code == StubCode::UnknownDartCode().ptr());
|
||||
}
|
||||
|
||||
void Code::DisableDartCode() const {
|
||||
|
||||
+109
-2
@@ -479,6 +479,9 @@ class Object {
|
||||
static ClassPtr instructions_section_class() {
|
||||
return instructions_section_class_;
|
||||
}
|
||||
static ClassPtr instructions_table_class() {
|
||||
return instructions_table_class_;
|
||||
}
|
||||
static ClassPtr object_pool_class() { return object_pool_class_; }
|
||||
static ClassPtr pc_descriptors_class() { return pc_descriptors_class_; }
|
||||
static ClassPtr code_source_map_class() { return code_source_map_class_; }
|
||||
@@ -790,6 +793,7 @@ class Object {
|
||||
|
||||
static ClassPtr instructions_class_; // Class of the Instructions vm object.
|
||||
static ClassPtr instructions_section_class_; // Class of InstructionsSection.
|
||||
static ClassPtr instructions_table_class_; // Class of InstructionsTable.
|
||||
static ClassPtr object_pool_class_; // Class of the ObjectPool vm object.
|
||||
static ClassPtr pc_descriptors_class_; // Class of PcDescriptors vm object.
|
||||
static ClassPtr code_source_map_class_; // Class of CodeSourceMap vm object.
|
||||
@@ -2662,6 +2666,8 @@ class Function : public Object {
|
||||
|
||||
static intptr_t code_offset() { return OFFSET_OF(UntaggedFunction, code_); }
|
||||
|
||||
uword entry_point() const { return untag()->entry_point_; }
|
||||
|
||||
static intptr_t entry_point_offset(
|
||||
CodeEntryKind entry_kind = CodeEntryKind::kNormal) {
|
||||
switch (entry_kind) {
|
||||
@@ -5402,6 +5408,107 @@ class InstructionsSection : public Object {
|
||||
friend class Class;
|
||||
};
|
||||
|
||||
// Table which maps ranges of machine code to [Code] or
|
||||
// [CompressedStackMaps] objects.
|
||||
// Used in AOT in bare instructions mode.
|
||||
class InstructionsTable : public Object {
|
||||
public:
|
||||
static const intptr_t kBytesPerElement = sizeof(uint32_t);
|
||||
static const intptr_t kMaxElements = kIntptrMax / kBytesPerElement;
|
||||
|
||||
static const uint32_t kHasMonomorphicEntrypointFlag = 0x1;
|
||||
static const uint32_t kPayloadAlignment = Instructions::kBarePayloadAlignment;
|
||||
static const uint32_t kPayloadMask = ~(kPayloadAlignment - 1);
|
||||
COMPILE_ASSERT((kPayloadMask & kHasMonomorphicEntrypointFlag) == 0);
|
||||
|
||||
static intptr_t InstanceSize() {
|
||||
ASSERT_EQUAL(sizeof(UntaggedInstructionsTable),
|
||||
OFFSET_OF_RETURNED_VALUE(UntaggedInstructionsTable, data));
|
||||
return 0;
|
||||
}
|
||||
static intptr_t InstanceSize(intptr_t len) {
|
||||
ASSERT(0 <= len && len <= kMaxElements);
|
||||
return RoundedAllocationSize(sizeof(UntaggedInstructionsTable) +
|
||||
len * kBytesPerElement);
|
||||
}
|
||||
|
||||
static InstructionsTablePtr New(intptr_t length,
|
||||
uword start_pc,
|
||||
uword end_pc);
|
||||
|
||||
void SetEntryAt(intptr_t index,
|
||||
uword payload_start,
|
||||
bool has_monomorphic_entrypoint,
|
||||
ObjectPtr descriptor) const;
|
||||
|
||||
bool ContainsPc(uword pc) const { return ContainsPc(ptr(), pc); }
|
||||
static bool ContainsPc(InstructionsTablePtr table, uword pc);
|
||||
|
||||
// Looks for the entry in the [table] by the given [pc].
|
||||
// Returns index of an entry which contains [pc], or -1 if not found.
|
||||
static intptr_t FindEntry(InstructionsTablePtr table, uword pc);
|
||||
|
||||
intptr_t length() const { return InstructionsTable::length(this->ptr()); }
|
||||
static intptr_t length(InstructionsTablePtr table) {
|
||||
return table->untag()->length_;
|
||||
}
|
||||
|
||||
// Returns descriptor object for the entry with given index.
|
||||
ObjectPtr DescriptorAt(intptr_t index) const {
|
||||
return InstructionsTable::DescriptorAt(this->ptr(), index);
|
||||
}
|
||||
static ObjectPtr DescriptorAt(InstructionsTablePtr table, intptr_t index);
|
||||
|
||||
// Returns start address of the instructions entry with given index.
|
||||
uword PayloadStartAt(intptr_t index) const {
|
||||
return InstructionsTable::PayloadStartAt(this->ptr(), index);
|
||||
}
|
||||
static uword PayloadStartAt(InstructionsTablePtr table, intptr_t index);
|
||||
|
||||
// Returns entry point of the instructions with given index.
|
||||
uword EntryPointAt(intptr_t index) const;
|
||||
|
||||
private:
|
||||
uword start_pc() const { return InstructionsTable::start_pc(this->ptr()); }
|
||||
static uword start_pc(InstructionsTablePtr table) {
|
||||
return table->untag()->start_pc_;
|
||||
}
|
||||
|
||||
uword end_pc() const { return InstructionsTable::end_pc(this->ptr()); }
|
||||
static uword end_pc(InstructionsTablePtr table) {
|
||||
return table->untag()->end_pc_;
|
||||
}
|
||||
|
||||
ArrayPtr descriptors() const { return untag()->descriptors_; }
|
||||
|
||||
static uint32_t DataAt(InstructionsTablePtr table, intptr_t index) {
|
||||
ASSERT((0 <= index) && (index < InstructionsTable::length(table)));
|
||||
return table->untag()->data()[index];
|
||||
}
|
||||
uint32_t PcOffsetAt(intptr_t index) const {
|
||||
return InstructionsTable::PcOffsetAt(this->ptr(), index);
|
||||
}
|
||||
static uint32_t PcOffsetAt(InstructionsTablePtr table, intptr_t index) {
|
||||
return DataAt(table, index) & kPayloadMask;
|
||||
}
|
||||
bool HasMonomorphicEntryPointAt(intptr_t index) const {
|
||||
return (DataAt(this->ptr(), index) & kHasMonomorphicEntrypointFlag) != 0;
|
||||
}
|
||||
|
||||
void set_length(intptr_t value) const;
|
||||
void set_start_pc(uword value) const;
|
||||
void set_end_pc(uword value) const;
|
||||
void set_descriptors(const Array& value) const;
|
||||
|
||||
uint32_t ConvertPcToOffset(uword pc) const {
|
||||
return InstructionsTable::ConvertPcToOffset(this->ptr(), pc);
|
||||
}
|
||||
static uint32_t ConvertPcToOffset(InstructionsTablePtr table, uword pc);
|
||||
|
||||
FINAL_HEAP_OBJECT_IMPLEMENTATION(InstructionsTable, Object);
|
||||
friend class Class;
|
||||
};
|
||||
|
||||
class LocalVarDescriptors : public Object {
|
||||
public:
|
||||
intptr_t Length() const;
|
||||
@@ -6412,8 +6519,8 @@ class Code : public Object {
|
||||
|
||||
// Set by precompiler if this Code object doesn't contain
|
||||
// useful information besides instructions and compressed stack map.
|
||||
// Such object is serialized in a shorter form. (In future such
|
||||
// Code objects will not be re-created during snapshot deserialization.)
|
||||
// Such objects are serialized in a shorter form and replaced with
|
||||
// StubCode::UnknownDartCode() during snapshot deserialization.
|
||||
class DiscardedBit : public BitField<int32_t, bool, kDiscardedBit, 1> {};
|
||||
|
||||
class PtrOffBits
|
||||
|
||||
@@ -1308,6 +1308,7 @@ uint32_t HeapSnapshotWriter::GetHeapSnapshotIdentityHash(Thread* thread,
|
||||
case kImmutableArrayCid:
|
||||
case kInstructionsCid:
|
||||
case kInstructionsSectionCid:
|
||||
case kInstructionsTableCid:
|
||||
case kLinkedHashMapCid:
|
||||
case kMintCid:
|
||||
case kNeverCid:
|
||||
|
||||
@@ -623,6 +623,10 @@ void InstructionsSection::PrintJSONImpl(JSONStream* stream, bool ref) const {
|
||||
Object::PrintJSONImpl(stream, ref);
|
||||
}
|
||||
|
||||
void InstructionsTable::PrintJSONImpl(JSONStream* stream, bool ref) const {
|
||||
Object::PrintJSONImpl(stream, ref);
|
||||
}
|
||||
|
||||
void WeakSerializationReference::PrintJSONImpl(JSONStream* stream,
|
||||
bool ref) const {
|
||||
JSONObject jsobj(stream);
|
||||
|
||||
@@ -231,7 +231,7 @@ class ObjectPointerVisitor;
|
||||
RW(Code, unreachable_tts_stub) \
|
||||
RW(Code, slow_tts_stub) \
|
||||
RW(Array, dispatch_table_code_entries) \
|
||||
RW(GrowableObjectArray, code_order_tables) \
|
||||
RW(GrowableObjectArray, instructions_tables) \
|
||||
RW(Array, obfuscation_map) \
|
||||
RW(GrowableObjectArray, ffi_callback_functions) \
|
||||
RW(Class, ffi_pointer_class) \
|
||||
|
||||
@@ -115,6 +115,13 @@ intptr_t UntaggedObject::HeapSizeFromClass(uword tags) const {
|
||||
instance_size = InstructionsSection::InstanceSize(section_size);
|
||||
break;
|
||||
}
|
||||
case kInstructionsTableCid: {
|
||||
const InstructionsTablePtr raw_instructions_table =
|
||||
static_cast<const InstructionsTablePtr>(this);
|
||||
intptr_t length = raw_instructions_table->untag()->length_;
|
||||
instance_size = InstructionsTable::InstanceSize(length);
|
||||
break;
|
||||
}
|
||||
case kContextCid: {
|
||||
const ContextPtr raw_context = static_cast<const ContextPtr>(this);
|
||||
intptr_t num_variables = raw_context->untag()->num_variables_;
|
||||
@@ -575,6 +582,7 @@ VARIABLE_COMPRESSED_VISITOR(
|
||||
TypedData::ElementSizeInBytes(raw_obj->GetClassId()) *
|
||||
Smi::Value(raw_obj->untag()->length()))
|
||||
VARIABLE_COMPRESSED_VISITOR(ContextScope, raw_obj->untag()->num_variables_)
|
||||
VARIABLE_VISITOR(InstructionsTable, raw_obj->untag()->length_)
|
||||
NULL_VISITOR(Mint)
|
||||
NULL_VISITOR(Double)
|
||||
NULL_VISITOR(Float32x4)
|
||||
|
||||
@@ -1835,6 +1835,22 @@ class UntaggedInstructionsSection : public UntaggedObject {
|
||||
friend class Image;
|
||||
};
|
||||
|
||||
class UntaggedInstructionsTable : public UntaggedObject {
|
||||
RAW_HEAP_OBJECT_IMPLEMENTATION(InstructionsTable);
|
||||
|
||||
VISIT_FROM(ObjectPtr, descriptors)
|
||||
POINTER_FIELD(ArrayPtr, descriptors)
|
||||
VISIT_TO_LENGTH(ObjectPtr, &descriptors_)
|
||||
|
||||
intptr_t length_;
|
||||
uword start_pc_;
|
||||
uword end_pc_;
|
||||
|
||||
// Variable length data follows here.
|
||||
uint32_t* data() { OPEN_ARRAY_START(uint32_t, uint32_t); }
|
||||
const uint32_t* data() const { OPEN_ARRAY_START(uint32_t, uint32_t); }
|
||||
};
|
||||
|
||||
class UntaggedPcDescriptors : public UntaggedObject {
|
||||
public:
|
||||
// The macro argument V is passed two arguments, the raw name of the enum value
|
||||
|
||||
@@ -106,6 +106,7 @@ namespace dart {
|
||||
F(CallSiteData, args_descriptor_) \
|
||||
F(ICData, entries_) \
|
||||
F(ICData, owner_) \
|
||||
F(InstructionsTable, descriptors_) \
|
||||
F(MegamorphicCache, buckets_) \
|
||||
F(MegamorphicCache, mask_) \
|
||||
F(SubtypeTestCache, cache_) \
|
||||
|
||||
@@ -549,6 +549,7 @@ MESSAGE_SNAPSHOT_UNREACHABLE(CallSiteData);
|
||||
MESSAGE_SNAPSHOT_UNREACHABLE(ICData);
|
||||
MESSAGE_SNAPSHOT_UNREACHABLE(Instructions);
|
||||
MESSAGE_SNAPSHOT_UNREACHABLE(InstructionsSection);
|
||||
MESSAGE_SNAPSHOT_UNREACHABLE(InstructionsTable);
|
||||
MESSAGE_SNAPSHOT_UNREACHABLE(KernelProgramInfo);
|
||||
MESSAGE_SNAPSHOT_UNREACHABLE(Library);
|
||||
MESSAGE_SNAPSHOT_UNREACHABLE(LibraryPrefix);
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/stub_code.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
CodePtr ReversePc::LookupInGroup(IsolateGroup* group,
|
||||
uword pc,
|
||||
bool is_return_address) {
|
||||
ObjectPtr ReversePc::FindCodeDescriptorInGroup(IsolateGroup* group,
|
||||
uword pc,
|
||||
bool is_return_address,
|
||||
uword* code_start) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
// This can run in the middle of GC and must not allocate handles.
|
||||
NoSafepointScope no_safepoint;
|
||||
@@ -21,50 +23,40 @@ CodePtr ReversePc::LookupInGroup(IsolateGroup* group,
|
||||
pc--;
|
||||
}
|
||||
|
||||
// This expected number of tables is low, so we go through them linearly. If
|
||||
// this changes, would could sort the table list during deserialization and
|
||||
// binary search for the table.
|
||||
GrowableObjectArrayPtr tables = group->object_store()->code_order_tables();
|
||||
// This expected number of tables is low (one per loading unit), so we go
|
||||
// through them linearly. If this changes, would could sort the table list
|
||||
// during deserialization and binary search for the table.
|
||||
GrowableObjectArrayPtr tables = group->object_store()->instructions_tables();
|
||||
intptr_t tables_length = Smi::Value(tables->untag()->length_);
|
||||
for (intptr_t i = 0; i < tables_length; i++) {
|
||||
ArrayPtr table =
|
||||
static_cast<ArrayPtr>(tables->untag()->data_->untag()->data()[i]);
|
||||
intptr_t lo = 0;
|
||||
intptr_t hi = Smi::Value(table->untag()->length_) - 1;
|
||||
|
||||
// Fast check if pc belongs to this table.
|
||||
if (lo > hi) {
|
||||
continue;
|
||||
}
|
||||
CodePtr first = static_cast<CodePtr>(table->untag()->data()[lo]);
|
||||
if (pc < Code::PayloadStartOf(first)) {
|
||||
continue;
|
||||
}
|
||||
CodePtr last = static_cast<CodePtr>(table->untag()->data()[hi]);
|
||||
if (pc >= (Code::PayloadStartOf(last) + Code::PayloadSizeOf(last))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Binary search within the table for the matching Code.
|
||||
while (lo <= hi) {
|
||||
intptr_t mid = (hi - lo + 1) / 2 + lo;
|
||||
ASSERT(mid >= lo);
|
||||
ASSERT(mid <= hi);
|
||||
CodePtr code = static_cast<CodePtr>(table->untag()->data()[mid]);
|
||||
uword code_start = Code::PayloadStartOf(code);
|
||||
uword code_end = code_start + Code::PayloadSizeOf(code);
|
||||
if (pc < code_start) {
|
||||
hi = mid - 1;
|
||||
} else if (pc >= code_end) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
return code;
|
||||
}
|
||||
InstructionsTablePtr table = static_cast<InstructionsTablePtr>(
|
||||
tables->untag()->data_->untag()->data()[i]);
|
||||
intptr_t index = InstructionsTable::FindEntry(table, pc);
|
||||
if (index >= 0) {
|
||||
*code_start = InstructionsTable::PayloadStartAt(table, index);
|
||||
return InstructionsTable::DescriptorAt(table, index);
|
||||
}
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
return Code::null();
|
||||
*code_start = 0;
|
||||
return Object::null();
|
||||
}
|
||||
|
||||
ObjectPtr ReversePc::FindCodeDescriptor(IsolateGroup* group,
|
||||
uword pc,
|
||||
bool is_return_address,
|
||||
uword* code_start) {
|
||||
ASSERT(FLAG_precompiled_mode && FLAG_use_bare_instructions);
|
||||
NoSafepointScope no_safepoint;
|
||||
|
||||
ObjectPtr code_descriptor =
|
||||
FindCodeDescriptorInGroup(group, pc, is_return_address, code_start);
|
||||
if (code_descriptor == Object::null()) {
|
||||
code_descriptor = FindCodeDescriptorInGroup(Dart::vm_isolate_group(), pc,
|
||||
is_return_address, code_start);
|
||||
}
|
||||
return code_descriptor;
|
||||
}
|
||||
|
||||
CodePtr ReversePc::Lookup(IsolateGroup* group,
|
||||
@@ -73,11 +65,19 @@ CodePtr ReversePc::Lookup(IsolateGroup* group,
|
||||
ASSERT(FLAG_precompiled_mode && FLAG_use_bare_instructions);
|
||||
NoSafepointScope no_safepoint;
|
||||
|
||||
CodePtr code = LookupInGroup(group, pc, is_return_address);
|
||||
if (code == Code::null()) {
|
||||
code = LookupInGroup(Dart::vm_isolate_group(), pc, is_return_address);
|
||||
uword code_start;
|
||||
ObjectPtr code_descriptor =
|
||||
FindCodeDescriptor(group, pc, is_return_address, &code_start);
|
||||
if (code_descriptor != Object::null()) {
|
||||
if (!code_descriptor->IsCode()) {
|
||||
ASSERT(StubCode::UnknownDartCode().PayloadStart() == 0);
|
||||
ASSERT(StubCode::UnknownDartCode().Size() == kUwordMax);
|
||||
ASSERT(StubCode::UnknownDartCode().IsFunctionCode());
|
||||
ASSERT(StubCode::UnknownDartCode().IsUnknownDartCode());
|
||||
code_descriptor = StubCode::UnknownDartCode().ptr();
|
||||
}
|
||||
}
|
||||
return code;
|
||||
return static_cast<CodePtr>(code_descriptor);
|
||||
}
|
||||
|
||||
CompressedStackMapsPtr ReversePc::FindCompressedStackMaps(
|
||||
@@ -88,10 +88,17 @@ CompressedStackMapsPtr ReversePc::FindCompressedStackMaps(
|
||||
ASSERT(FLAG_precompiled_mode && FLAG_use_bare_instructions);
|
||||
NoSafepointScope no_safepoint;
|
||||
|
||||
CodePtr code = Lookup(group, pc, is_return_address);
|
||||
if (code != Code::null()) {
|
||||
*code_start = Code::PayloadStartOf(code);
|
||||
return code->untag()->compressed_stackmaps();
|
||||
ObjectPtr code_descriptor =
|
||||
FindCodeDescriptor(group, pc, is_return_address, code_start);
|
||||
if (code_descriptor != Object::null()) {
|
||||
if (code_descriptor->IsCode()) {
|
||||
CodePtr code = static_cast<CodePtr>(code_descriptor);
|
||||
ASSERT(*code_start == Code::PayloadStartOf(code));
|
||||
return code->untag()->compressed_stackmaps();
|
||||
} else {
|
||||
ASSERT(code_descriptor->IsCompressedStackMaps());
|
||||
return static_cast<CompressedStackMapsPtr>(code_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
*code_start = 0;
|
||||
|
||||
@@ -32,9 +32,14 @@ class ReversePc : public AllStatic {
|
||||
uword* code_start);
|
||||
|
||||
private:
|
||||
static CodePtr LookupInGroup(IsolateGroup* group,
|
||||
uword pc,
|
||||
bool is_return_address);
|
||||
static ObjectPtr FindCodeDescriptorInGroup(IsolateGroup* group,
|
||||
uword pc,
|
||||
bool is_return_address,
|
||||
uword* code_start);
|
||||
static ObjectPtr FindCodeDescriptor(IsolateGroup* group,
|
||||
uword pc,
|
||||
bool is_return_address,
|
||||
uword* code_start);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -351,24 +351,10 @@ CodePtr StackFrame::GetCodeObject() const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
|
||||
NoSafepointScope no_safepoint;
|
||||
Code code;
|
||||
code = ReversePc::Lookup(isolate_group(), pc(),
|
||||
/*is_return_address=*/true);
|
||||
if (!code.IsNull()) {
|
||||
// This is needed in order to test stack traces with the future
|
||||
// behavior of ReversePc::Lookup which will return
|
||||
// StubCode::UnknownDartCode() if code object is omitted from
|
||||
// the snapshot.
|
||||
if (code.is_discarded()) {
|
||||
ASSERT(StubCode::UnknownDartCode().PayloadStart() == 0);
|
||||
ASSERT(StubCode::UnknownDartCode().Size() == kUwordMax);
|
||||
ASSERT(StubCode::UnknownDartCode().IsFunctionCode());
|
||||
ASSERT(StubCode::UnknownDartCode().IsUnknownDartCode());
|
||||
return StubCode::UnknownDartCode().ptr();
|
||||
}
|
||||
return code.ptr();
|
||||
}
|
||||
UNREACHABLE();
|
||||
CodePtr code = ReversePc::Lookup(isolate_group(), pc(),
|
||||
/*is_return_address=*/true);
|
||||
ASSERT(code != Code::null());
|
||||
return code;
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
|
||||
@@ -186,6 +186,7 @@ class ObjectPointerVisitor;
|
||||
V(InitPrefix, "init:") \
|
||||
V(Instructions, "Instructions") \
|
||||
V(InstructionsSection, "InstructionsSection") \
|
||||
V(InstructionsTable, "InstructionsTable") \
|
||||
V(Int, "int") \
|
||||
V(Int16List, "Int16List") \
|
||||
V(Int32List, "Int32List") \
|
||||
|
||||
@@ -300,6 +300,7 @@ DEFINE_TAGGED_POINTER(Code, Object)
|
||||
DEFINE_TAGGED_POINTER(ObjectPool, Object)
|
||||
DEFINE_TAGGED_POINTER(Instructions, Object)
|
||||
DEFINE_TAGGED_POINTER(InstructionsSection, Object)
|
||||
DEFINE_TAGGED_POINTER(InstructionsTable, Object)
|
||||
DEFINE_TAGGED_POINTER(PcDescriptors, Object)
|
||||
DEFINE_TAGGED_POINTER(CodeSourceMap, Object)
|
||||
DEFINE_TAGGED_POINTER(CompressedStackMaps, Object)
|
||||
|
||||
@@ -224,8 +224,8 @@ static void RunTTSTest(
|
||||
auto& stc2 = SubtypeTestCache::Handle();
|
||||
|
||||
// First invocation will a) specialize the TTS b) may create SubtypeTestCache
|
||||
result = DartEntry::InvokeCode(invoke_tts, arguments_descriptor, arguments,
|
||||
thread);
|
||||
result = DartEntry::InvokeCode(invoke_tts, invoke_tts.EntryPoint(),
|
||||
arguments_descriptor, arguments, thread);
|
||||
stc ^= pool.ObjectAt(kSubtypeTestCacheIndex);
|
||||
tts = instantiated_dst_type.type_test_stub();
|
||||
if (!result.IsError()) {
|
||||
@@ -234,8 +234,8 @@ static void RunTTSTest(
|
||||
lazy(result, stc);
|
||||
|
||||
// Second invocation will a) keep TTS b) keep optional SubtypeTestCache
|
||||
result2 = DartEntry::InvokeCode(invoke_tts, arguments_descriptor, arguments,
|
||||
thread);
|
||||
result2 = DartEntry::InvokeCode(invoke_tts, invoke_tts.EntryPoint(),
|
||||
arguments_descriptor, arguments, thread);
|
||||
stc2 ^= pool.ObjectAt(kSubtypeTestCacheIndex);
|
||||
tts2 = instantiated_dst_type.type_test_stub();
|
||||
abi_regs_modified ^= abi_regs_modified_box.At(0);
|
||||
@@ -252,8 +252,8 @@ static void RunTTSTest(
|
||||
TypeTestingStubGenerator::SpecializeStubFor(thread, instantiated_dst_type);
|
||||
tts = instantiated_dst_type.type_test_stub();
|
||||
|
||||
result2 = DartEntry::InvokeCode(invoke_tts, arguments_descriptor, arguments,
|
||||
thread);
|
||||
result2 = DartEntry::InvokeCode(invoke_tts, invoke_tts.EntryPoint(),
|
||||
arguments_descriptor, arguments, thread);
|
||||
stc2 ^= pool.ObjectAt(kSubtypeTestCacheIndex);
|
||||
tts2 = instantiated_dst_type.type_test_stub();
|
||||
abi_regs_modified ^= abi_regs_modified_box.At(0);
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.
|
||||
|
||||
// VMOptions=
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
apply(Function function, List? positional, Map<Symbol, dynamic>? named) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// VMOptions=--intrinsify --enable-asserts
|
||||
// VMOptions=--no-intrinsify --enable-asserts
|
||||
// VMOptions=--optimization-counter-threshold=5 --no-background-compilation
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.
|
||||
|
||||
// VMOptions=
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
apply(Function function, List positional, Map<Symbol, dynamic> named) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// VMOptions=--intrinsify --enable-asserts
|
||||
// VMOptions=--no-intrinsify --enable-asserts
|
||||
// VMOptions=--optimization-counter-threshold=5 --no-background-compilation
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.
|
||||
|
||||
// VMOptions=
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import 'dart:async' as async;
|
||||
import 'lib.dart' as l; // Minimal library containing "int async;".
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.
|
||||
|
||||
// VMOptions=
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import 'function_type_lib.dart' deferred as lib;
|
||||
|
||||
main() {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.
|
||||
|
||||
// VMOptions=
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "package:async_helper/async_helper.dart";
|
||||
import "shared_and_unshared_classes_lib1.dart" deferred as lib1;
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.
|
||||
|
||||
// VMOptions=
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import 'dart:async' as async;
|
||||
import 'lib.dart' as l; // Minimal library containing "int async;".
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.
|
||||
|
||||
// VMOptions=
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import 'function_type_lib.dart' deferred as lib;
|
||||
|
||||
main() {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.
|
||||
|
||||
// VMOptions=
|
||||
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "package:async_helper/async_helper.dart";
|
||||
import "shared_and_unshared_classes_lib1.dart" deferred as lib1;
|
||||
|
||||
Reference in New Issue
Block a user