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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « runtime/vm/program_visitor.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/program_visitor.h" 5 #include "vm/program_visitor.h"
6 6
7 #include "vm/deopt_instructions.h"
7 #include "vm/object.h" 8 #include "vm/object.h"
8 #include "vm/object_store.h" 9 #include "vm/object_store.h"
10 #include "vm/hash_map.h"
11 #include "vm/symbols.h"
9 12
10 namespace dart { 13 namespace dart {
11 14
12 void ProgramVisitor::VisitClasses(ClassVisitor* visitor) { 15 void ProgramVisitor::VisitClasses(ClassVisitor* visitor) {
13 Thread* thread = Thread::Current(); 16 Thread* thread = Thread::Current();
14 Isolate* isolate = thread->isolate(); 17 Isolate* isolate = thread->isolate();
15 Zone* zone = thread->zone(); 18 Zone* zone = thread->zone();
16 GrowableObjectArray& libraries = 19 GrowableObjectArray& libraries =
17 GrowableObjectArray::Handle(zone, isolate->object_store()->libraries()); 20 GrowableObjectArray::Handle(zone, isolate->object_store()->libraries());
18 Library& lib = Library::Handle(zone); 21 Library& lib = Library::Handle(zone);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 } 88 }
86 } 89 }
87 closures = isolate->object_store()->closure_functions(); 90 closures = isolate->object_store()->closure_functions();
88 for (intptr_t j = 0; j < closures.Length(); j++) { 91 for (intptr_t j = 0; j < closures.Length(); j++) {
89 function ^= closures.At(j); 92 function ^= closures.At(j);
90 visitor->Visit(function); 93 visitor->Visit(function);
91 ASSERT(!function.HasImplicitClosureFunction()); 94 ASSERT(!function.HasImplicitClosureFunction());
92 } 95 }
93 } 96 }
94 97
98
99 void ProgramVisitor::ShareMegamorphicBuckets() {
100 Thread* thread = Thread::Current();
101 Isolate* isolate = thread->isolate();
102 Zone* zone = thread->zone();
103
104 const GrowableObjectArray& table = GrowableObjectArray::Handle(
105 zone, isolate->object_store()->megamorphic_cache_table());
106 if (table.IsNull()) return;
107 MegamorphicCache& cache = MegamorphicCache::Handle(zone);
108
109 const intptr_t capacity = 1;
110 const Array& buckets = Array::Handle(
111 zone, Array::New(MegamorphicCache::kEntryLength * capacity, Heap::kOld));
112 const Function& handler =
113 Function::Handle(zone, MegamorphicCacheTable::miss_handler(isolate));
114 MegamorphicCache::SetEntry(buckets, 0, MegamorphicCache::smi_illegal_cid(),
115 handler);
116
117 for (intptr_t i = 0; i < table.Length(); i++) {
118 cache ^= table.At(i);
119 cache.set_buckets(buckets);
120 cache.set_mask(capacity - 1);
121 cache.set_filled_entry_count(0);
122 }
123 }
124
125
126 class StackMapKeyValueTrait {
127 public:
128 // Typedefs needed for the DirectChainedHashMap template.
129 typedef const StackMap* Key;
130 typedef const StackMap* Value;
131 typedef const StackMap* Pair;
132
133 static Key KeyOf(Pair kv) { return kv; }
134
135 static Value ValueOf(Pair kv) { return kv; }
136
137 static inline intptr_t Hashcode(Key key) { return key->PcOffset(); }
138
139 static inline bool IsKeyEqual(Pair pair, Key key) {
140 return pair->Equals(*key);
141 }
142 };
143
144 typedef DirectChainedHashMap<StackMapKeyValueTrait> StackMapSet;
145
146
147 void ProgramVisitor::DedupStackMaps() {
148 class DedupStackMapsVisitor : public FunctionVisitor {
149 public:
150 explicit DedupStackMapsVisitor(Zone* zone)
151 : zone_(zone),
152 canonical_stackmaps_(),
153 code_(Code::Handle(zone)),
154 stackmaps_(Array::Handle(zone)),
155 stackmap_(StackMap::Handle(zone)) {}
156
157 void Visit(const Function& function) {
158 if (!function.HasCode()) {
159 return;
160 }
161 code_ = function.CurrentCode();
162 stackmaps_ = code_.stackmaps();
163 if (stackmaps_.IsNull()) return;
164 for (intptr_t i = 0; i < stackmaps_.Length(); i++) {
165 stackmap_ ^= stackmaps_.At(i);
166 stackmap_ = DedupStackMap(stackmap_);
167 stackmaps_.SetAt(i, stackmap_);
168 }
169 }
170
171 RawStackMap* DedupStackMap(const StackMap& stackmap) {
172 const StackMap* canonical_stackmap =
173 canonical_stackmaps_.LookupValue(&stackmap);
174 if (canonical_stackmap == NULL) {
175 canonical_stackmaps_.Insert(
176 &StackMap::ZoneHandle(zone_, stackmap.raw()));
177 return stackmap.raw();
178 } else {
179 return canonical_stackmap->raw();
180 }
181 }
182
183 private:
184 Zone* zone_;
185 StackMapSet canonical_stackmaps_;
186 Code& code_;
187 Array& stackmaps_;
188 StackMap& stackmap_;
189 };
190
191 DedupStackMapsVisitor visitor(Thread::Current()->zone());
192 ProgramVisitor::VisitFunctions(&visitor);
193 }
194
195
196 class PcDescriptorsKeyValueTrait {
197 public:
198 // Typedefs needed for the DirectChainedHashMap template.
199 typedef const PcDescriptors* Key;
200 typedef const PcDescriptors* Value;
201 typedef const PcDescriptors* Pair;
202
203 static Key KeyOf(Pair kv) { return kv; }
204
205 static Value ValueOf(Pair kv) { return kv; }
206
207 static inline intptr_t Hashcode(Key key) { return key->Length(); }
208
209 static inline bool IsKeyEqual(Pair pair, Key key) {
210 return pair->Equals(*key);
211 }
212 };
213
214 typedef DirectChainedHashMap<PcDescriptorsKeyValueTrait> PcDescriptorsSet;
215
216
217 void ProgramVisitor::DedupPcDescriptors() {
218 class DedupPcDescriptorsVisitor : public FunctionVisitor {
219 public:
220 explicit DedupPcDescriptorsVisitor(Zone* zone)
221 : zone_(zone),
222 canonical_pc_descriptors_(),
223 code_(Code::Handle(zone)),
224 pc_descriptor_(PcDescriptors::Handle(zone)) {}
225
226 void Visit(const Function& function) {
227 if (!function.HasCode()) {
228 return;
229 }
230 code_ = function.CurrentCode();
231 pc_descriptor_ = code_.pc_descriptors();
232 if (pc_descriptor_.IsNull()) return;
233 pc_descriptor_ = DedupPcDescriptor(pc_descriptor_);
234 code_.set_pc_descriptors(pc_descriptor_);
235 }
236
237 RawPcDescriptors* DedupPcDescriptor(const PcDescriptors& pc_descriptor) {
238 const PcDescriptors* canonical_pc_descriptor =
239 canonical_pc_descriptors_.LookupValue(&pc_descriptor);
240 if (canonical_pc_descriptor == NULL) {
241 canonical_pc_descriptors_.Insert(
242 &PcDescriptors::ZoneHandle(zone_, pc_descriptor.raw()));
243 return pc_descriptor.raw();
244 } else {
245 return canonical_pc_descriptor->raw();
246 }
247 }
248
249 private:
250 Zone* zone_;
251 PcDescriptorsSet canonical_pc_descriptors_;
252 Code& code_;
253 PcDescriptors& pc_descriptor_;
254 };
255
256 DedupPcDescriptorsVisitor visitor(Thread::Current()->zone());
257 ProgramVisitor::VisitFunctions(&visitor);
258 }
259
260
261 class TypedDataKeyValueTrait {
262 public:
263 // Typedefs needed for the DirectChainedHashMap template.
264 typedef const TypedData* Key;
265 typedef const TypedData* Value;
266 typedef const TypedData* Pair;
267
268 static Key KeyOf(Pair kv) { return kv; }
269
270 static Value ValueOf(Pair kv) { return kv; }
271
272 static inline intptr_t Hashcode(Key key) {
273 return key->ComputeCanonicalTableHash();
274 }
275
276 static inline bool IsKeyEqual(Pair pair, Key key) {
277 return pair->CanonicalizeEquals(*key);
278 }
279 };
280
281 typedef DirectChainedHashMap<TypedDataKeyValueTrait> TypedDataSet;
282
283
284 void ProgramVisitor::DedupDeoptEntries() {
285 class DedupDeoptEntriesVisitor : public FunctionVisitor {
286 public:
287 explicit DedupDeoptEntriesVisitor(Zone* zone)
288 : zone_(zone),
289 canonical_deopt_entries_(),
290 code_(Code::Handle(zone)),
291 deopt_table_(Array::Handle(zone)),
292 deopt_entry_(TypedData::Handle(zone)),
293 offset_(Smi::Handle(zone)),
294 reason_and_flags_(Smi::Handle(zone)) {}
295
296 void Visit(const Function& function) {
297 if (!function.HasCode()) {
298 return;
299 }
300 code_ = function.CurrentCode();
301 deopt_table_ = code_.deopt_info_array();
302 if (deopt_table_.IsNull()) return;
303 intptr_t length = DeoptTable::GetLength(deopt_table_);
304 for (intptr_t i = 0; i < length; i++) {
305 DeoptTable::GetEntry(deopt_table_, i, &offset_, &deopt_entry_,
306 &reason_and_flags_);
307 ASSERT(!deopt_entry_.IsNull());
308 deopt_entry_ = DedupDeoptEntry(deopt_entry_);
309 ASSERT(!deopt_entry_.IsNull());
310 DeoptTable::SetEntry(deopt_table_, i, offset_, deopt_entry_,
311 reason_and_flags_);
312 }
313 }
314
315 RawTypedData* DedupDeoptEntry(const TypedData& deopt_entry) {
316 const TypedData* canonical_deopt_entry =
317 canonical_deopt_entries_.LookupValue(&deopt_entry);
318 if (canonical_deopt_entry == NULL) {
319 canonical_deopt_entries_.Insert(
320 &TypedData::ZoneHandle(zone_, deopt_entry.raw()));
321 return deopt_entry.raw();
322 } else {
323 return canonical_deopt_entry->raw();
324 }
325 }
326
327 private:
328 Zone* zone_;
329 TypedDataSet canonical_deopt_entries_;
330 Code& code_;
331 Array& deopt_table_;
332 TypedData& deopt_entry_;
333 Smi& offset_;
334 Smi& reason_and_flags_;
335 };
336
337 DedupDeoptEntriesVisitor visitor(Thread::Current()->zone());
338 ProgramVisitor::VisitFunctions(&visitor);
339 }
340
341
342 class CodeSourceMapKeyValueTrait {
343 public:
344 // Typedefs needed for the DirectChainedHashMap template.
345 typedef const CodeSourceMap* Key;
346 typedef const CodeSourceMap* Value;
347 typedef const CodeSourceMap* Pair;
348
349 static Key KeyOf(Pair kv) { return kv; }
350
351 static Value ValueOf(Pair kv) { return kv; }
352
353 static inline intptr_t Hashcode(Key key) { return key->Length(); }
354
355 static inline bool IsKeyEqual(Pair pair, Key key) {
356 return pair->Equals(*key);
357 }
358 };
359
360 typedef DirectChainedHashMap<CodeSourceMapKeyValueTrait> CodeSourceMapSet;
361
362
363 void ProgramVisitor::DedupCodeSourceMaps() {
364 class DedupCodeSourceMapsVisitor : public FunctionVisitor {
365 public:
366 explicit DedupCodeSourceMapsVisitor(Zone* zone)
367 : zone_(zone),
368 canonical_code_source_maps_(),
369 code_(Code::Handle(zone)),
370 code_source_map_(CodeSourceMap::Handle(zone)) {}
371
372 void Visit(const Function& function) {
373 if (!function.HasCode()) {
374 return;
375 }
376 code_ = function.CurrentCode();
377 code_source_map_ = code_.code_source_map();
378 ASSERT(!code_source_map_.IsNull());
379 code_source_map_ = DedupCodeSourceMap(code_source_map_);
380 code_.set_code_source_map(code_source_map_);
381 }
382
383 RawCodeSourceMap* DedupCodeSourceMap(const CodeSourceMap& code_source_map) {
384 const CodeSourceMap* canonical_code_source_map =
385 canonical_code_source_maps_.LookupValue(&code_source_map);
386 if (canonical_code_source_map == NULL) {
387 canonical_code_source_maps_.Insert(
388 &CodeSourceMap::ZoneHandle(zone_, code_source_map.raw()));
389 return code_source_map.raw();
390 } else {
391 return canonical_code_source_map->raw();
392 }
393 }
394
395 private:
396 Zone* zone_;
397 CodeSourceMapSet canonical_code_source_maps_;
398 Code& code_;
399 CodeSourceMap& code_source_map_;
400 };
401
402 DedupCodeSourceMapsVisitor visitor(Thread::Current()->zone());
403 ProgramVisitor::VisitFunctions(&visitor);
404 }
405
406
407 class ArrayKeyValueTrait {
408 public:
409 // Typedefs needed for the DirectChainedHashMap template.
410 typedef const Array* Key;
411 typedef const Array* Value;
412 typedef const Array* Pair;
413
414 static Key KeyOf(Pair kv) { return kv; }
415
416 static Value ValueOf(Pair kv) { return kv; }
417
418 static inline intptr_t Hashcode(Key key) { return key->Length(); }
419
420 static inline bool IsKeyEqual(Pair pair, Key key) {
421 if (pair->Length() != key->Length()) {
422 return false;
423 }
424 for (intptr_t i = 0; i < pair->Length(); i++) {
425 if (pair->At(i) != key->At(i)) {
426 return false;
427 }
428 }
429 return true;
430 }
431 };
432
433 typedef DirectChainedHashMap<ArrayKeyValueTrait> ArraySet;
434
435
436 void ProgramVisitor::DedupLists() {
437 class DedupListsVisitor : public FunctionVisitor {
438 public:
439 DedupListsVisitor(Isolate* isolate, Zone* zone)
440 : isolate_(isolate),
441 zone_(zone),
442 canonical_lists_(),
443 code_(Code::Handle(zone)),
444 list_(Array::Handle(zone)) {}
445
446 void Visit(const Function& function) {
447 code_ = function.CurrentCode();
448 if (!code_.IsNull()) {
449 list_ = code_.stackmaps();
450 if (!list_.IsNull()) {
451 list_ = DedupList(list_);
452 code_.set_stackmaps(list_);
453 }
454 list_ = code_.inlined_id_to_function();
455 if (!list_.IsNull()) {
456 list_ = DedupList(list_);
457 code_.set_inlined_id_to_function(list_);
458 }
459 list_ = code_.deopt_info_array();
460 if (!list_.IsNull()) {
461 list_ = DedupList(list_);
462 code_.set_deopt_info_array(list_);
463 }
464 #ifndef PRODUCT
465 list_ = code_.await_token_positions();
466 if (!list_.IsNull()) {
467 list_ = DedupList(list_);
468 code_.set_await_token_positions(list_);
469 }
470 #endif // !PRODUCT
471 list_ = code_.static_calls_target_table();
472 if (!list_.IsNull()) {
473 list_ = DedupList(list_);
474 code_.set_static_calls_target_table(list_);
475 }
476 }
477
478 list_ = function.parameter_types();
479 if (!list_.IsNull()) {
480 // Preserve parameter types in case of recompilation in JIT checked
481 // mode, or if available to mirrors.
482 if (FLAG_precompiled_mode ||
483 (!FLAG_enable_mirrors && !isolate_->type_checks())) {
484 if (!function.IsSignatureFunction() &&
485 !function.IsClosureFunction() &&
486 (function.name() != Symbols::Call().raw()) && !list_.InVMHeap()) {
487 // Parameter types not needed for function type tests.
488 for (intptr_t i = 0; i < list_.Length(); i++) {
489 list_.SetAt(i, Object::dynamic_type());
490 }
491 }
492 }
493 list_ = DedupList(list_);
494 function.set_parameter_types(list_);
495 }
496
497 list_ = function.parameter_names();
498 if (!list_.IsNull()) {
499 // Preserve parameter names in case of recompilation for the JIT.
500 if (FLAG_precompiled_mode) {
501 if (!function.HasOptionalNamedParameters() && !list_.InVMHeap()) {
502 // Parameter names not needed for resolution.
503 for (intptr_t i = 0; i < list_.Length(); i++) {
504 list_.SetAt(i, Symbols::OptimizedOut());
505 }
506 }
507 }
508 list_ = DedupList(list_);
509 function.set_parameter_names(list_);
510 }
511 }
512
513 RawArray* DedupList(const Array& list) {
514 const Array* canonical_list = canonical_lists_.LookupValue(&list);
515 if (canonical_list == NULL) {
516 canonical_lists_.Insert(&Array::ZoneHandle(zone_, list.raw()));
517 return list.raw();
518 } else {
519 return canonical_list->raw();
520 }
521 }
522
523 private:
524 Isolate* isolate_;
525 Zone* zone_;
526 ArraySet canonical_lists_;
527 Code& code_;
528 Array& list_;
529 };
530
531 Thread* thread = Thread::Current();
532 DedupListsVisitor visitor(thread->isolate(), thread->zone());
533 ProgramVisitor::VisitFunctions(&visitor);
534 }
535
536
537 class InstructionsKeyValueTrait {
538 public:
539 // Typedefs needed for the DirectChainedHashMap template.
540 typedef const Instructions* Key;
541 typedef const Instructions* Value;
542 typedef const Instructions* Pair;
543
544 static Key KeyOf(Pair kv) { return kv; }
545
546 static Value ValueOf(Pair kv) { return kv; }
547
548 static inline intptr_t Hashcode(Key key) { return key->Size(); }
549
550 static inline bool IsKeyEqual(Pair pair, Key key) {
551 return pair->Equals(*key);
552 }
553 };
554
555 typedef DirectChainedHashMap<InstructionsKeyValueTrait> InstructionsSet;
556
557
558 void ProgramVisitor::DedupInstructions() {
559 class DedupInstructionsVisitor : public FunctionVisitor {
560 public:
561 explicit DedupInstructionsVisitor(Zone* zone)
562 : zone_(zone),
563 canonical_instructions_set_(),
564 code_(Code::Handle(zone)),
565 instructions_(Instructions::Handle(zone)) {}
566
567 void Visit(const Function& function) {
568 if (!function.HasCode()) {
569 ASSERT(function.HasImplicitClosureFunction());
570 return;
571 }
572 code_ = function.CurrentCode();
573 instructions_ = code_.instructions();
574 instructions_ = DedupOneInstructions(instructions_);
575 code_.SetActiveInstructions(instructions_);
576 code_.set_instructions(instructions_);
577 function.SetInstructions(code_); // Update cached entry point.
578 }
579
580 RawInstructions* DedupOneInstructions(const Instructions& instructions) {
581 const Instructions* canonical_instructions =
582 canonical_instructions_set_.LookupValue(&instructions);
583 if (canonical_instructions == NULL) {
584 canonical_instructions_set_.Insert(
585 &Instructions::ZoneHandle(zone_, instructions.raw()));
586 return instructions.raw();
587 } else {
588 return canonical_instructions->raw();
589 }
590 }
591
592 private:
593 Zone* zone_;
594 InstructionsSet canonical_instructions_set_;
595 Code& code_;
596 Instructions& instructions_;
597 };
598
599 DedupInstructionsVisitor visitor(Thread::Current()->zone());
600 ProgramVisitor::VisitFunctions(&visitor);
601 }
602
603
604 void ProgramVisitor::Dedup() {
605 Thread* thread = Thread::Current();
606 StackZone stack_zone(thread);
607 HANDLESCOPE(thread);
608
609 // TODO(rmacnak): Bind static calls whose target has been compiled. Forward
610 // references to disabled code.
611 ShareMegamorphicBuckets();
612 DedupStackMaps();
613 DedupPcDescriptors();
614 DedupDeoptEntries();
615 DedupCodeSourceMaps();
616 DedupLists();
617
618 if (!FLAG_profiler) {
619 // Reduces binary size but obfuscates profiler results.
620 DedupInstructions();
621 }
622 }
623
95 } // namespace dart 624 } // namespace dart
OLDNEW
« 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