Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(143)

Unified Diff: runtime/vm/program_visitor.cc

Issue 2815533003: Refactor AOT deduplication steps so they can run before an app-jit snapshot as well. (Closed)
Patch Set: . Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/program_visitor.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/program_visitor.cc
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index 4a41925b7f74bd9abcabaa6b80478ebf18f876f8..cfeb9a41262d9ddc596a4572e8093ebe9c0d3afd 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -4,8 +4,11 @@
#include "vm/program_visitor.h"
+#include "vm/deopt_instructions.h"
#include "vm/object.h"
#include "vm/object_store.h"
+#include "vm/hash_map.h"
+#include "vm/symbols.h"
namespace dart {
@@ -92,4 +95,530 @@ void ProgramVisitor::VisitFunctions(FunctionVisitor* visitor) {
}
}
+
+void ProgramVisitor::ShareMegamorphicBuckets() {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ Zone* zone = thread->zone();
+
+ const GrowableObjectArray& table = GrowableObjectArray::Handle(
+ zone, isolate->object_store()->megamorphic_cache_table());
+ if (table.IsNull()) return;
+ MegamorphicCache& cache = MegamorphicCache::Handle(zone);
+
+ const intptr_t capacity = 1;
+ const Array& buckets = Array::Handle(
+ zone, Array::New(MegamorphicCache::kEntryLength * capacity, Heap::kOld));
+ const Function& handler =
+ Function::Handle(zone, MegamorphicCacheTable::miss_handler(isolate));
+ MegamorphicCache::SetEntry(buckets, 0, MegamorphicCache::smi_illegal_cid(),
+ handler);
+
+ for (intptr_t i = 0; i < table.Length(); i++) {
+ cache ^= table.At(i);
+ cache.set_buckets(buckets);
+ cache.set_mask(capacity - 1);
+ cache.set_filled_entry_count(0);
+ }
+}
+
+
+class StackMapKeyValueTrait {
+ public:
+ // Typedefs needed for the DirectChainedHashMap template.
+ typedef const StackMap* Key;
+ typedef const StackMap* Value;
+ typedef const StackMap* Pair;
+
+ static Key KeyOf(Pair kv) { return kv; }
+
+ static Value ValueOf(Pair kv) { return kv; }
+
+ static inline intptr_t Hashcode(Key key) { return key->PcOffset(); }
+
+ static inline bool IsKeyEqual(Pair pair, Key key) {
+ return pair->Equals(*key);
+ }
+};
+
+typedef DirectChainedHashMap<StackMapKeyValueTrait> StackMapSet;
+
+
+void ProgramVisitor::DedupStackMaps() {
+ class DedupStackMapsVisitor : public FunctionVisitor {
+ public:
+ explicit DedupStackMapsVisitor(Zone* zone)
+ : zone_(zone),
+ canonical_stackmaps_(),
+ code_(Code::Handle(zone)),
+ stackmaps_(Array::Handle(zone)),
+ stackmap_(StackMap::Handle(zone)) {}
+
+ void Visit(const Function& function) {
+ if (!function.HasCode()) {
+ return;
+ }
+ code_ = function.CurrentCode();
+ stackmaps_ = code_.stackmaps();
+ if (stackmaps_.IsNull()) return;
+ for (intptr_t i = 0; i < stackmaps_.Length(); i++) {
+ stackmap_ ^= stackmaps_.At(i);
+ stackmap_ = DedupStackMap(stackmap_);
+ stackmaps_.SetAt(i, stackmap_);
+ }
+ }
+
+ RawStackMap* DedupStackMap(const StackMap& stackmap) {
+ const StackMap* canonical_stackmap =
+ canonical_stackmaps_.LookupValue(&stackmap);
+ if (canonical_stackmap == NULL) {
+ canonical_stackmaps_.Insert(
+ &StackMap::ZoneHandle(zone_, stackmap.raw()));
+ return stackmap.raw();
+ } else {
+ return canonical_stackmap->raw();
+ }
+ }
+
+ private:
+ Zone* zone_;
+ StackMapSet canonical_stackmaps_;
+ Code& code_;
+ Array& stackmaps_;
+ StackMap& stackmap_;
+ };
+
+ DedupStackMapsVisitor visitor(Thread::Current()->zone());
+ ProgramVisitor::VisitFunctions(&visitor);
+}
+
+
+class PcDescriptorsKeyValueTrait {
+ public:
+ // Typedefs needed for the DirectChainedHashMap template.
+ typedef const PcDescriptors* Key;
+ typedef const PcDescriptors* Value;
+ typedef const PcDescriptors* Pair;
+
+ static Key KeyOf(Pair kv) { return kv; }
+
+ static Value ValueOf(Pair kv) { return kv; }
+
+ static inline intptr_t Hashcode(Key key) { return key->Length(); }
+
+ static inline bool IsKeyEqual(Pair pair, Key key) {
+ return pair->Equals(*key);
+ }
+};
+
+typedef DirectChainedHashMap<PcDescriptorsKeyValueTrait> PcDescriptorsSet;
+
+
+void ProgramVisitor::DedupPcDescriptors() {
+ class DedupPcDescriptorsVisitor : public FunctionVisitor {
+ public:
+ explicit DedupPcDescriptorsVisitor(Zone* zone)
+ : zone_(zone),
+ canonical_pc_descriptors_(),
+ code_(Code::Handle(zone)),
+ pc_descriptor_(PcDescriptors::Handle(zone)) {}
+
+ void Visit(const Function& function) {
+ if (!function.HasCode()) {
+ return;
+ }
+ code_ = function.CurrentCode();
+ pc_descriptor_ = code_.pc_descriptors();
+ if (pc_descriptor_.IsNull()) return;
+ pc_descriptor_ = DedupPcDescriptor(pc_descriptor_);
+ code_.set_pc_descriptors(pc_descriptor_);
+ }
+
+ RawPcDescriptors* DedupPcDescriptor(const PcDescriptors& pc_descriptor) {
+ const PcDescriptors* canonical_pc_descriptor =
+ canonical_pc_descriptors_.LookupValue(&pc_descriptor);
+ if (canonical_pc_descriptor == NULL) {
+ canonical_pc_descriptors_.Insert(
+ &PcDescriptors::ZoneHandle(zone_, pc_descriptor.raw()));
+ return pc_descriptor.raw();
+ } else {
+ return canonical_pc_descriptor->raw();
+ }
+ }
+
+ private:
+ Zone* zone_;
+ PcDescriptorsSet canonical_pc_descriptors_;
+ Code& code_;
+ PcDescriptors& pc_descriptor_;
+ };
+
+ DedupPcDescriptorsVisitor visitor(Thread::Current()->zone());
+ ProgramVisitor::VisitFunctions(&visitor);
+}
+
+
+class TypedDataKeyValueTrait {
+ public:
+ // Typedefs needed for the DirectChainedHashMap template.
+ typedef const TypedData* Key;
+ typedef const TypedData* Value;
+ typedef const TypedData* Pair;
+
+ static Key KeyOf(Pair kv) { return kv; }
+
+ static Value ValueOf(Pair kv) { return kv; }
+
+ static inline intptr_t Hashcode(Key key) {
+ return key->ComputeCanonicalTableHash();
+ }
+
+ static inline bool IsKeyEqual(Pair pair, Key key) {
+ return pair->CanonicalizeEquals(*key);
+ }
+};
+
+typedef DirectChainedHashMap<TypedDataKeyValueTrait> TypedDataSet;
+
+
+void ProgramVisitor::DedupDeoptEntries() {
+ class DedupDeoptEntriesVisitor : public FunctionVisitor {
+ public:
+ explicit DedupDeoptEntriesVisitor(Zone* zone)
+ : zone_(zone),
+ canonical_deopt_entries_(),
+ code_(Code::Handle(zone)),
+ deopt_table_(Array::Handle(zone)),
+ deopt_entry_(TypedData::Handle(zone)),
+ offset_(Smi::Handle(zone)),
+ reason_and_flags_(Smi::Handle(zone)) {}
+
+ void Visit(const Function& function) {
+ if (!function.HasCode()) {
+ return;
+ }
+ code_ = function.CurrentCode();
+ deopt_table_ = code_.deopt_info_array();
+ if (deopt_table_.IsNull()) return;
+ intptr_t length = DeoptTable::GetLength(deopt_table_);
+ for (intptr_t i = 0; i < length; i++) {
+ DeoptTable::GetEntry(deopt_table_, i, &offset_, &deopt_entry_,
+ &reason_and_flags_);
+ ASSERT(!deopt_entry_.IsNull());
+ deopt_entry_ = DedupDeoptEntry(deopt_entry_);
+ ASSERT(!deopt_entry_.IsNull());
+ DeoptTable::SetEntry(deopt_table_, i, offset_, deopt_entry_,
+ reason_and_flags_);
+ }
+ }
+
+ RawTypedData* DedupDeoptEntry(const TypedData& deopt_entry) {
+ const TypedData* canonical_deopt_entry =
+ canonical_deopt_entries_.LookupValue(&deopt_entry);
+ if (canonical_deopt_entry == NULL) {
+ canonical_deopt_entries_.Insert(
+ &TypedData::ZoneHandle(zone_, deopt_entry.raw()));
+ return deopt_entry.raw();
+ } else {
+ return canonical_deopt_entry->raw();
+ }
+ }
+
+ private:
+ Zone* zone_;
+ TypedDataSet canonical_deopt_entries_;
+ Code& code_;
+ Array& deopt_table_;
+ TypedData& deopt_entry_;
+ Smi& offset_;
+ Smi& reason_and_flags_;
+ };
+
+ DedupDeoptEntriesVisitor visitor(Thread::Current()->zone());
+ ProgramVisitor::VisitFunctions(&visitor);
+}
+
+
+class CodeSourceMapKeyValueTrait {
+ public:
+ // Typedefs needed for the DirectChainedHashMap template.
+ typedef const CodeSourceMap* Key;
+ typedef const CodeSourceMap* Value;
+ typedef const CodeSourceMap* Pair;
+
+ static Key KeyOf(Pair kv) { return kv; }
+
+ static Value ValueOf(Pair kv) { return kv; }
+
+ static inline intptr_t Hashcode(Key key) { return key->Length(); }
+
+ static inline bool IsKeyEqual(Pair pair, Key key) {
+ return pair->Equals(*key);
+ }
+};
+
+typedef DirectChainedHashMap<CodeSourceMapKeyValueTrait> CodeSourceMapSet;
+
+
+void ProgramVisitor::DedupCodeSourceMaps() {
+ class DedupCodeSourceMapsVisitor : public FunctionVisitor {
+ public:
+ explicit DedupCodeSourceMapsVisitor(Zone* zone)
+ : zone_(zone),
+ canonical_code_source_maps_(),
+ code_(Code::Handle(zone)),
+ code_source_map_(CodeSourceMap::Handle(zone)) {}
+
+ void Visit(const Function& function) {
+ if (!function.HasCode()) {
+ return;
+ }
+ code_ = function.CurrentCode();
+ code_source_map_ = code_.code_source_map();
+ ASSERT(!code_source_map_.IsNull());
+ code_source_map_ = DedupCodeSourceMap(code_source_map_);
+ code_.set_code_source_map(code_source_map_);
+ }
+
+ RawCodeSourceMap* DedupCodeSourceMap(const CodeSourceMap& code_source_map) {
+ const CodeSourceMap* canonical_code_source_map =
+ canonical_code_source_maps_.LookupValue(&code_source_map);
+ if (canonical_code_source_map == NULL) {
+ canonical_code_source_maps_.Insert(
+ &CodeSourceMap::ZoneHandle(zone_, code_source_map.raw()));
+ return code_source_map.raw();
+ } else {
+ return canonical_code_source_map->raw();
+ }
+ }
+
+ private:
+ Zone* zone_;
+ CodeSourceMapSet canonical_code_source_maps_;
+ Code& code_;
+ CodeSourceMap& code_source_map_;
+ };
+
+ DedupCodeSourceMapsVisitor visitor(Thread::Current()->zone());
+ ProgramVisitor::VisitFunctions(&visitor);
+}
+
+
+class ArrayKeyValueTrait {
+ public:
+ // Typedefs needed for the DirectChainedHashMap template.
+ typedef const Array* Key;
+ typedef const Array* Value;
+ typedef const Array* Pair;
+
+ static Key KeyOf(Pair kv) { return kv; }
+
+ static Value ValueOf(Pair kv) { return kv; }
+
+ static inline intptr_t Hashcode(Key key) { return key->Length(); }
+
+ static inline bool IsKeyEqual(Pair pair, Key key) {
+ if (pair->Length() != key->Length()) {
+ return false;
+ }
+ for (intptr_t i = 0; i < pair->Length(); i++) {
+ if (pair->At(i) != key->At(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+typedef DirectChainedHashMap<ArrayKeyValueTrait> ArraySet;
+
+
+void ProgramVisitor::DedupLists() {
+ class DedupListsVisitor : public FunctionVisitor {
+ public:
+ DedupListsVisitor(Isolate* isolate, Zone* zone)
+ : isolate_(isolate),
+ zone_(zone),
+ canonical_lists_(),
+ code_(Code::Handle(zone)),
+ list_(Array::Handle(zone)) {}
+
+ void Visit(const Function& function) {
+ code_ = function.CurrentCode();
+ if (!code_.IsNull()) {
+ list_ = code_.stackmaps();
+ if (!list_.IsNull()) {
+ list_ = DedupList(list_);
+ code_.set_stackmaps(list_);
+ }
+ list_ = code_.inlined_id_to_function();
+ if (!list_.IsNull()) {
+ list_ = DedupList(list_);
+ code_.set_inlined_id_to_function(list_);
+ }
+ list_ = code_.deopt_info_array();
+ if (!list_.IsNull()) {
+ list_ = DedupList(list_);
+ code_.set_deopt_info_array(list_);
+ }
+#ifndef PRODUCT
+ list_ = code_.await_token_positions();
+ if (!list_.IsNull()) {
+ list_ = DedupList(list_);
+ code_.set_await_token_positions(list_);
+ }
+#endif // !PRODUCT
+ list_ = code_.static_calls_target_table();
+ if (!list_.IsNull()) {
+ list_ = DedupList(list_);
+ code_.set_static_calls_target_table(list_);
+ }
+ }
+
+ list_ = function.parameter_types();
+ if (!list_.IsNull()) {
+ // Preserve parameter types in case of recompilation in JIT checked
+ // mode, or if available to mirrors.
+ if (FLAG_precompiled_mode ||
+ (!FLAG_enable_mirrors && !isolate_->type_checks())) {
+ if (!function.IsSignatureFunction() &&
+ !function.IsClosureFunction() &&
+ (function.name() != Symbols::Call().raw()) && !list_.InVMHeap()) {
+ // Parameter types not needed for function type tests.
+ for (intptr_t i = 0; i < list_.Length(); i++) {
+ list_.SetAt(i, Object::dynamic_type());
+ }
+ }
+ }
+ list_ = DedupList(list_);
+ function.set_parameter_types(list_);
+ }
+
+ list_ = function.parameter_names();
+ if (!list_.IsNull()) {
+ // Preserve parameter names in case of recompilation for the JIT.
+ if (FLAG_precompiled_mode) {
+ if (!function.HasOptionalNamedParameters() && !list_.InVMHeap()) {
+ // Parameter names not needed for resolution.
+ for (intptr_t i = 0; i < list_.Length(); i++) {
+ list_.SetAt(i, Symbols::OptimizedOut());
+ }
+ }
+ }
+ list_ = DedupList(list_);
+ function.set_parameter_names(list_);
+ }
+ }
+
+ RawArray* DedupList(const Array& list) {
+ const Array* canonical_list = canonical_lists_.LookupValue(&list);
+ if (canonical_list == NULL) {
+ canonical_lists_.Insert(&Array::ZoneHandle(zone_, list.raw()));
+ return list.raw();
+ } else {
+ return canonical_list->raw();
+ }
+ }
+
+ private:
+ Isolate* isolate_;
+ Zone* zone_;
+ ArraySet canonical_lists_;
+ Code& code_;
+ Array& list_;
+ };
+
+ Thread* thread = Thread::Current();
+ DedupListsVisitor visitor(thread->isolate(), thread->zone());
+ ProgramVisitor::VisitFunctions(&visitor);
+}
+
+
+class InstructionsKeyValueTrait {
+ public:
+ // Typedefs needed for the DirectChainedHashMap template.
+ typedef const Instructions* Key;
+ typedef const Instructions* Value;
+ typedef const Instructions* Pair;
+
+ static Key KeyOf(Pair kv) { return kv; }
+
+ static Value ValueOf(Pair kv) { return kv; }
+
+ static inline intptr_t Hashcode(Key key) { return key->Size(); }
+
+ static inline bool IsKeyEqual(Pair pair, Key key) {
+ return pair->Equals(*key);
+ }
+};
+
+typedef DirectChainedHashMap<InstructionsKeyValueTrait> InstructionsSet;
+
+
+void ProgramVisitor::DedupInstructions() {
+ class DedupInstructionsVisitor : public FunctionVisitor {
+ public:
+ explicit DedupInstructionsVisitor(Zone* zone)
+ : zone_(zone),
+ canonical_instructions_set_(),
+ code_(Code::Handle(zone)),
+ instructions_(Instructions::Handle(zone)) {}
+
+ void Visit(const Function& function) {
+ if (!function.HasCode()) {
+ ASSERT(function.HasImplicitClosureFunction());
+ return;
+ }
+ code_ = function.CurrentCode();
+ instructions_ = code_.instructions();
+ instructions_ = DedupOneInstructions(instructions_);
+ code_.SetActiveInstructions(instructions_);
+ code_.set_instructions(instructions_);
+ function.SetInstructions(code_); // Update cached entry point.
+ }
+
+ RawInstructions* DedupOneInstructions(const Instructions& instructions) {
+ const Instructions* canonical_instructions =
+ canonical_instructions_set_.LookupValue(&instructions);
+ if (canonical_instructions == NULL) {
+ canonical_instructions_set_.Insert(
+ &Instructions::ZoneHandle(zone_, instructions.raw()));
+ return instructions.raw();
+ } else {
+ return canonical_instructions->raw();
+ }
+ }
+
+ private:
+ Zone* zone_;
+ InstructionsSet canonical_instructions_set_;
+ Code& code_;
+ Instructions& instructions_;
+ };
+
+ DedupInstructionsVisitor visitor(Thread::Current()->zone());
+ ProgramVisitor::VisitFunctions(&visitor);
+}
+
+
+void ProgramVisitor::Dedup() {
+ Thread* thread = Thread::Current();
+ StackZone stack_zone(thread);
+ HANDLESCOPE(thread);
+
+ // TODO(rmacnak): Bind static calls whose target has been compiled. Forward
+ // references to disabled code.
+ ShareMegamorphicBuckets();
+ DedupStackMaps();
+ DedupPcDescriptors();
+ DedupDeoptEntries();
+ DedupCodeSourceMaps();
+ DedupLists();
+
+ if (!FLAG_profiler) {
+ // Reduces binary size but obfuscates profiler results.
+ DedupInstructions();
+ }
+}
+
} // namespace dart
« no previous file with comments | « runtime/vm/program_visitor.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698