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