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

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 deopt_entry_ = DedupDeoptEntry(deopt_entry_);
308 DeoptTable::SetEntry(deopt_table_, i, offset_, deopt_entry_,
309 reason_and_flags_);
siva 2017/04/12 18:25:31 Not important but just an observation that if Dedu
rmacnak 2017/04/12 21:18:12 It should never return a null. Added assert.
310 }
311 }
312
313 RawTypedData* DedupDeoptEntry(const TypedData& deopt_entry) {
314 const TypedData* canonical_deopt_entry =
315 canonical_deopt_entries_.LookupValue(&deopt_entry);
316 if (canonical_deopt_entry == NULL) {
317 canonical_deopt_entries_.Insert(
318 &TypedData::ZoneHandle(zone_, deopt_entry.raw()));
319 return deopt_entry.raw();
320 } else {
321 return canonical_deopt_entry->raw();
322 }
323 }
324
325 private:
326 Zone* zone_;
327 TypedDataSet canonical_deopt_entries_;
328 Code& code_;
329 Array& deopt_table_;
330 TypedData& deopt_entry_;
331 Smi& offset_;
332 Smi& reason_and_flags_;
333 };
334
335 DedupDeoptEntriesVisitor visitor(Thread::Current()->zone());
336 ProgramVisitor::VisitFunctions(&visitor);
337 }
338
339
340 class CodeSourceMapKeyValueTrait {
341 public:
342 // Typedefs needed for the DirectChainedHashMap template.
343 typedef const CodeSourceMap* Key;
344 typedef const CodeSourceMap* Value;
345 typedef const CodeSourceMap* Pair;
346
347 static Key KeyOf(Pair kv) { return kv; }
348
349 static Value ValueOf(Pair kv) { return kv; }
350
351 static inline intptr_t Hashcode(Key key) { return key->Length(); }
352
353 static inline bool IsKeyEqual(Pair pair, Key key) {
354 return pair->Equals(*key);
355 }
356 };
357
358 typedef DirectChainedHashMap<CodeSourceMapKeyValueTrait> CodeSourceMapSet;
359
360
361 void ProgramVisitor::DedupCodeSourceMaps() {
362 class DedupCodeSourceMapsVisitor : public FunctionVisitor {
363 public:
364 explicit DedupCodeSourceMapsVisitor(Zone* zone)
365 : zone_(zone),
366 canonical_code_source_maps_(),
367 code_(Code::Handle(zone)),
368 code_source_map_(CodeSourceMap::Handle(zone)) {}
369
370 void Visit(const Function& function) {
371 if (!function.HasCode()) {
372 return;
373 }
374 code_ = function.CurrentCode();
375 code_source_map_ = code_.code_source_map();
376 ASSERT(!code_source_map_.IsNull());
377 code_source_map_ = DedupCodeSourceMap(code_source_map_);
378 code_.set_code_source_map(code_source_map_);
379 }
380
381 RawCodeSourceMap* DedupCodeSourceMap(const CodeSourceMap& code_source_map) {
382 const CodeSourceMap* canonical_code_source_map =
383 canonical_code_source_maps_.LookupValue(&code_source_map);
384 if (canonical_code_source_map == NULL) {
385 canonical_code_source_maps_.Insert(
386 &CodeSourceMap::ZoneHandle(zone_, code_source_map.raw()));
387 return code_source_map.raw();
388 } else {
389 return canonical_code_source_map->raw();
390 }
391 }
392
393 private:
394 Zone* zone_;
395 CodeSourceMapSet canonical_code_source_maps_;
396 Code& code_;
397 CodeSourceMap& code_source_map_;
398 };
399
400 DedupCodeSourceMapsVisitor visitor(Thread::Current()->zone());
401 ProgramVisitor::VisitFunctions(&visitor);
402 }
403
404
405 class ArrayKeyValueTrait {
406 public:
407 // Typedefs needed for the DirectChainedHashMap template.
408 typedef const Array* Key;
409 typedef const Array* Value;
410 typedef const Array* Pair;
411
412 static Key KeyOf(Pair kv) { return kv; }
413
414 static Value ValueOf(Pair kv) { return kv; }
415
416 static inline intptr_t Hashcode(Key key) { return key->Length(); }
417
418 static inline bool IsKeyEqual(Pair pair, Key key) {
419 if (pair->Length() != key->Length()) {
420 return false;
421 }
422 for (intptr_t i = 0; i < pair->Length(); i++) {
423 if (pair->At(i) != key->At(i)) {
424 return false;
425 }
426 }
427 return true;
428 }
429 };
430
431 typedef DirectChainedHashMap<ArrayKeyValueTrait> ArraySet;
432
433
434 void ProgramVisitor::DedupLists() {
435 class DedupListsVisitor : public FunctionVisitor {
436 public:
437 DedupListsVisitor(Isolate* isolate, Zone* zone)
438 : isolate_(isolate),
439 zone_(zone),
440 canonical_lists_(),
441 code_(Code::Handle(zone)),
442 list_(Array::Handle(zone)) {}
443
444 void Visit(const Function& function) {
445 code_ = function.CurrentCode();
446 if (!code_.IsNull()) {
447 list_ = code_.stackmaps();
448 if (!list_.IsNull()) {
449 list_ = DedupList(list_);
450 code_.set_stackmaps(list_);
451 }
452 list_ = code_.inlined_id_to_function();
453 if (!list_.IsNull()) {
454 list_ = DedupList(list_);
455 code_.set_inlined_id_to_function(list_);
456 }
457 list_ = code_.deopt_info_array();
458 if (!list_.IsNull()) {
459 list_ = DedupList(list_);
460 code_.set_deopt_info_array(list_);
461 }
462 #ifndef PRODUCT
463 list_ = code_.await_token_positions();
464 if (!list_.IsNull()) {
465 list_ = DedupList(list_);
466 code_.set_await_token_positions(list_);
467 }
468 #endif // !PRODUCT
469 list_ = code_.static_calls_target_table();
470 if (!list_.IsNull()) {
471 list_ = DedupList(list_);
472 code_.set_static_calls_target_table(list_);
473 }
474 }
475
476 list_ = function.parameter_types();
477 if (!list_.IsNull()) {
478 // Preserve parameter types in case of recompilation in JIT checked
479 // mode, or if available to mirrors.
480 if (FLAG_precompiled_mode ||
481 (!FLAG_enable_mirrors && !isolate_->type_checks())) {
482 if (!function.IsSignatureFunction() &&
483 !function.IsClosureFunction() &&
484 (function.name() != Symbols::Call().raw()) && !list_.InVMHeap()) {
485 // Parameter types not needed for function type tests.
486 for (intptr_t i = 0; i < list_.Length(); i++) {
487 list_.SetAt(i, Object::dynamic_type());
488 }
489 }
490 }
491 list_ = DedupList(list_);
492 function.set_parameter_types(list_);
493 }
494
495 list_ = function.parameter_names();
496 if (!list_.IsNull()) {
497 // Preserve parameter names in case of recompilation for the JIT.
498 if (FLAG_precompiled_mode) {
499 if (!function.HasOptionalNamedParameters() && !list_.InVMHeap()) {
500 // Parameter names not needed for resolution.
501 for (intptr_t i = 0; i < list_.Length(); i++) {
502 list_.SetAt(i, Symbols::OptimizedOut());
503 }
504 }
505 }
506 list_ = DedupList(list_);
507 function.set_parameter_names(list_);
508 }
509 }
510
511 RawArray* DedupList(const Array& list) {
512 const Array* canonical_list = canonical_lists_.LookupValue(&list);
513 if (canonical_list == NULL) {
514 canonical_lists_.Insert(&Array::ZoneHandle(zone_, list.raw()));
515 return list.raw();
516 } else {
517 return canonical_list->raw();
518 }
519 }
520
521 private:
522 Isolate* isolate_;
523 Zone* zone_;
524 ArraySet canonical_lists_;
525 Code& code_;
526 Array& list_;
527 };
528
529 Thread* thread = Thread::Current();
530 DedupListsVisitor visitor(thread->isolate(), thread->zone());
531 ProgramVisitor::VisitFunctions(&visitor);
532 }
533
534
535 class InstructionsKeyValueTrait {
536 public:
537 // Typedefs needed for the DirectChainedHashMap template.
538 typedef const Instructions* Key;
539 typedef const Instructions* Value;
540 typedef const Instructions* Pair;
541
542 static Key KeyOf(Pair kv) { return kv; }
543
544 static Value ValueOf(Pair kv) { return kv; }
545
546 static inline intptr_t Hashcode(Key key) { return key->Size(); }
547
548 static inline bool IsKeyEqual(Pair pair, Key key) {
549 return pair->Equals(*key);
550 }
551 };
552
553 typedef DirectChainedHashMap<InstructionsKeyValueTrait> InstructionsSet;
554
555
556 void ProgramVisitor::DedupInstructions() {
557 class DedupInstructionsVisitor : public FunctionVisitor {
558 public:
559 explicit DedupInstructionsVisitor(Zone* zone)
560 : zone_(zone),
561 canonical_instructions_set_(),
562 code_(Code::Handle(zone)),
563 instructions_(Instructions::Handle(zone)) {}
564
565 void Visit(const Function& function) {
566 if (!function.HasCode()) {
567 ASSERT(function.HasImplicitClosureFunction());
568 return;
569 }
570 code_ = function.CurrentCode();
571 instructions_ = code_.instructions();
572 instructions_ = DedupOneInstructions(instructions_);
573 code_.SetActiveInstructions(instructions_);
574 code_.set_instructions(instructions_);
575 function.SetInstructions(code_); // Update cached entry point.
576 }
577
578 RawInstructions* DedupOneInstructions(const Instructions& instructions) {
579 const Instructions* canonical_instructions =
580 canonical_instructions_set_.LookupValue(&instructions);
581 if (canonical_instructions == NULL) {
582 canonical_instructions_set_.Insert(
583 &Instructions::ZoneHandle(zone_, instructions.raw()));
584 return instructions.raw();
585 } else {
586 return canonical_instructions->raw();
587 }
588 }
589
590 private:
591 Zone* zone_;
592 InstructionsSet canonical_instructions_set_;
593 Code& code_;
594 Instructions& instructions_;
595 };
596
597 DedupInstructionsVisitor visitor(Thread::Current()->zone());
598 ProgramVisitor::VisitFunctions(&visitor);
599 }
600
601
602 void ProgramVisitor::Dedup() {
603 Thread* thread = Thread::Current();
604 StackZone stack_zone(thread);
605 HANDLESCOPE(thread);
606
607 // TODO(rmacnak): Bind static calls whose target has been compiled. Forward
608 // references to disabled code.
609 ShareMegamorphicBuckets();
610 DedupStackMaps();
611 DedupPcDescriptors();
612 DedupDeoptEntries();
613 DedupCodeSourceMaps();
614 DedupLists();
615
616 if (!FLAG_profiler) {
617 // Reduces binary size but obfuscates profiler results.
618 DedupInstructions();
619 }
620 }
621
95 } // namespace dart 622 } // 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