Chromium Code Reviews| 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 |