OLD | NEW |
---|---|
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 Loading... | |
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 |
OLD | NEW |