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/precompiler.h" | 5 #include "vm/precompiler.h" |
6 | 6 |
7 #include "vm/aot_optimizer.h" | 7 #include "vm/aot_optimizer.h" |
8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/ast_printer.h" | 9 #include "vm/ast_printer.h" |
10 #include "vm/branch_optimizer.h" | 10 #include "vm/branch_optimizer.h" |
11 #include "vm/cha.h" | 11 #include "vm/cha.h" |
| 12 #include "vm/class_finalizer.h" |
12 #include "vm/code_generator.h" | 13 #include "vm/code_generator.h" |
13 #include "vm/code_patcher.h" | 14 #include "vm/code_patcher.h" |
14 #include "vm/compiler.h" | 15 #include "vm/compiler.h" |
15 #include "vm/constant_propagator.h" | 16 #include "vm/constant_propagator.h" |
16 #include "vm/dart_entry.h" | 17 #include "vm/dart_entry.h" |
17 #include "vm/disassembler.h" | 18 #include "vm/disassembler.h" |
18 #include "vm/exceptions.h" | 19 #include "vm/exceptions.h" |
19 #include "vm/flags.h" | 20 #include "vm/flags.h" |
20 #include "vm/flow_graph.h" | 21 #include "vm/flow_graph.h" |
21 #include "vm/flow_graph_allocator.h" | 22 #include "vm/flow_graph_allocator.h" |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 StackZone stack_zone(T); | 421 StackZone stack_zone(T); |
421 zone_ = stack_zone.GetZone(); | 422 zone_ = stack_zone.GetZone(); |
422 | 423 |
423 { | 424 { |
424 HANDLESCOPE(T); | 425 HANDLESCOPE(T); |
425 // Make sure class hierarchy is stable before compilation so that CHA | 426 // Make sure class hierarchy is stable before compilation so that CHA |
426 // can be used. Also ensures lookup of entry points won't miss functions | 427 // can be used. Also ensures lookup of entry points won't miss functions |
427 // because their class hasn't been finalized yet. | 428 // because their class hasn't been finalized yet. |
428 FinalizeAllClasses(); | 429 FinalizeAllClasses(); |
429 | 430 |
430 SortClasses(); | 431 ClassFinalizer::SortClasses(); |
431 TypeRangeCache trc(this, T, I->class_table()->NumCids()); | 432 TypeRangeCache trc(this, T, I->class_table()->NumCids()); |
432 VerifyJITFeedback(); | 433 VerifyJITFeedback(); |
433 | 434 |
434 // Precompile static initializers to compute result type information. | 435 // Precompile static initializers to compute result type information. |
435 PrecompileStaticInitializers(); | 436 PrecompileStaticInitializers(); |
436 | 437 |
437 // Precompile constructors to compute type information for final fields. | 438 // Precompile constructors to compute type information for final fields. |
438 ClearAllCode(); | 439 ClassFinalizer::ClearAllCode(); |
439 PrecompileConstructors(); | 440 PrecompileConstructors(); |
440 | 441 |
441 for (intptr_t round = 0; round < FLAG_precompiler_rounds; round++) { | 442 for (intptr_t round = 0; round < FLAG_precompiler_rounds; round++) { |
442 if (FLAG_trace_precompiler) { | 443 if (FLAG_trace_precompiler) { |
443 THR_Print("Precompiler round %" Pd "\n", round); | 444 THR_Print("Precompiler round %" Pd "\n", round); |
444 } | 445 } |
445 | 446 |
446 if (round > 0) { | 447 if (round > 0) { |
447 ResetPrecompilerState(); | 448 ResetPrecompilerState(); |
448 } | 449 } |
449 | 450 |
450 // TODO(rmacnak): We should be able to do a more thorough job and drop | 451 // TODO(rmacnak): We should be able to do a more thorough job and drop |
451 // some | 452 // some |
452 // - implicit static closures | 453 // - implicit static closures |
453 // - field initializers | 454 // - field initializers |
454 // - invoke-field-dispatchers | 455 // - invoke-field-dispatchers |
455 // - method-extractors | 456 // - method-extractors |
456 // that are needed in early iterations but optimized away in later | 457 // that are needed in early iterations but optimized away in later |
457 // iterations. | 458 // iterations. |
458 ClearAllCode(); | 459 ClassFinalizer::ClearAllCode(); |
459 | 460 |
460 CollectDynamicFunctionNames(); | 461 CollectDynamicFunctionNames(); |
461 | 462 |
462 // Start with the allocations and invocations that happen from C++. | 463 // Start with the allocations and invocations that happen from C++. |
463 AddRoots(embedder_entry_points); | 464 AddRoots(embedder_entry_points); |
464 | 465 |
465 // Compile newly found targets and add their callees until we reach a | 466 // Compile newly found targets and add their callees until we reach a |
466 // fixed point. | 467 // fixed point. |
467 Iterate(); | 468 Iterate(); |
468 } | 469 } |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 current->field_->set_is_nullable(cid == kNullCid || cid == kDynamicCid); | 613 current->field_->set_is_nullable(cid == kNullCid || cid == kDynamicCid); |
613 if (FLAG_trace_precompiler) { | 614 if (FLAG_trace_precompiler) { |
614 THR_Print( | 615 THR_Print( |
615 "Field %s <- Type %s\n", current->field_->ToCString(), | 616 "Field %s <- Type %s\n", current->field_->ToCString(), |
616 Class::Handle(T->isolate()->class_table()->At(cid)).ToCString()); | 617 Class::Handle(T->isolate()->class_table()->At(cid)).ToCString()); |
617 } | 618 } |
618 } | 619 } |
619 } | 620 } |
620 | 621 |
621 | 622 |
622 void Precompiler::ClearAllCode() { | |
623 class ClearCodeFunctionVisitor : public FunctionVisitor { | |
624 void Visit(const Function& function) { | |
625 function.ClearCode(); | |
626 function.ClearICDataArray(); | |
627 } | |
628 }; | |
629 ClearCodeFunctionVisitor function_visitor; | |
630 ProgramVisitor::VisitFunctions(&function_visitor); | |
631 | |
632 class ClearCodeClassVisitor : public ClassVisitor { | |
633 void Visit(const Class& cls) { cls.DisableAllocationStub(); } | |
634 }; | |
635 ClearCodeClassVisitor class_visitor; | |
636 ProgramVisitor::VisitClasses(&class_visitor); | |
637 } | |
638 | |
639 | |
640 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) { | 623 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) { |
641 // Note that <rootlibrary>.main is not a root. The appropriate main will be | 624 // Note that <rootlibrary>.main is not a root. The appropriate main will be |
642 // discovered through _getMainClosure. | 625 // discovered through _getMainClosure. |
643 | 626 |
644 AddSelector(Symbols::NoSuchMethod()); | 627 AddSelector(Symbols::NoSuchMethod()); |
645 | 628 |
646 AddSelector(Symbols::Call()); // For speed, not correctness. | 629 AddSelector(Symbols::Call()); // For speed, not correctness. |
647 | 630 |
648 // Allocated from C++. | 631 // Allocated from C++. |
649 Class& cls = Class::Handle(Z); | 632 Class& cls = Class::Handle(Z); |
(...skipping 1886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2536 error_ = cls.EnsureIsFinalized(T); | 2519 error_ = cls.EnsureIsFinalized(T); |
2537 if (!error_.IsNull()) { | 2520 if (!error_.IsNull()) { |
2538 Jump(error_); | 2521 Jump(error_); |
2539 } | 2522 } |
2540 } | 2523 } |
2541 } | 2524 } |
2542 I->set_all_classes_finalized(true); | 2525 I->set_all_classes_finalized(true); |
2543 } | 2526 } |
2544 | 2527 |
2545 | 2528 |
2546 void Precompiler::SortClasses() { | |
2547 ClassTable* table = I->class_table(); | |
2548 intptr_t num_cids = table->NumCids(); | |
2549 intptr_t* old_to_new_cid = new intptr_t[num_cids]; | |
2550 for (intptr_t cid = 0; cid < kNumPredefinedCids; cid++) { | |
2551 old_to_new_cid[cid] = cid; // The predefined classes cannot change cids. | |
2552 } | |
2553 for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) { | |
2554 old_to_new_cid[cid] = -1; | |
2555 } | |
2556 | |
2557 intptr_t next_new_cid = kNumPredefinedCids; | |
2558 GrowableArray<intptr_t> dfs_stack; | |
2559 Class& cls = Class::Handle(Z); | |
2560 GrowableObjectArray& subclasses = GrowableObjectArray::Handle(Z); | |
2561 | |
2562 // Object doesn't use its subclasses list. | |
2563 for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) { | |
2564 if (!table->HasValidClassAt(cid)) { | |
2565 continue; | |
2566 } | |
2567 cls = table->At(cid); | |
2568 if (cls.is_patch()) { | |
2569 continue; | |
2570 } | |
2571 if (cls.SuperClass() == I->object_store()->object_class()) { | |
2572 dfs_stack.Add(cid); | |
2573 } | |
2574 } | |
2575 | |
2576 while (dfs_stack.length() > 0) { | |
2577 intptr_t cid = dfs_stack.RemoveLast(); | |
2578 ASSERT(table->HasValidClassAt(cid)); | |
2579 cls = table->At(cid); | |
2580 ASSERT(!cls.IsNull()); | |
2581 if (old_to_new_cid[cid] == -1) { | |
2582 old_to_new_cid[cid] = next_new_cid++; | |
2583 if (FLAG_trace_precompiler) { | |
2584 THR_Print("%" Pd ": %s, was %" Pd "\n", old_to_new_cid[cid], | |
2585 cls.ToCString(), cid); | |
2586 } | |
2587 } | |
2588 subclasses = cls.direct_subclasses(); | |
2589 if (!subclasses.IsNull()) { | |
2590 for (intptr_t i = 0; i < subclasses.Length(); i++) { | |
2591 cls ^= subclasses.At(i); | |
2592 ASSERT(!cls.IsNull()); | |
2593 dfs_stack.Add(cls.id()); | |
2594 } | |
2595 } | |
2596 } | |
2597 | |
2598 // Top-level classes, typedefs, patch classes, etc. | |
2599 for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) { | |
2600 if (old_to_new_cid[cid] == -1) { | |
2601 old_to_new_cid[cid] = next_new_cid++; | |
2602 if (FLAG_trace_precompiler && table->HasValidClassAt(cid)) { | |
2603 cls = table->At(cid); | |
2604 THR_Print("%" Pd ": %s, was %" Pd "\n", old_to_new_cid[cid], | |
2605 cls.ToCString(), cid); | |
2606 } | |
2607 } | |
2608 } | |
2609 ASSERT(next_new_cid == num_cids); | |
2610 | |
2611 RemapClassIds(old_to_new_cid); | |
2612 delete[] old_to_new_cid; | |
2613 RehashTypes(); // Types use cid's as part of their hashes. | |
2614 } | |
2615 | |
2616 | |
2617 class CidRewriteVisitor : public ObjectVisitor { | |
2618 public: | |
2619 explicit CidRewriteVisitor(intptr_t* old_to_new_cids) | |
2620 : old_to_new_cids_(old_to_new_cids) {} | |
2621 | |
2622 intptr_t Map(intptr_t cid) { | |
2623 ASSERT(cid != -1); | |
2624 return old_to_new_cids_[cid]; | |
2625 } | |
2626 | |
2627 void VisitObject(RawObject* obj) { | |
2628 if (obj->IsClass()) { | |
2629 RawClass* cls = Class::RawCast(obj); | |
2630 cls->ptr()->id_ = Map(cls->ptr()->id_); | |
2631 } else if (obj->IsField()) { | |
2632 RawField* field = Field::RawCast(obj); | |
2633 field->ptr()->guarded_cid_ = Map(field->ptr()->guarded_cid_); | |
2634 field->ptr()->is_nullable_ = Map(field->ptr()->is_nullable_); | |
2635 } else if (obj->IsTypeParameter()) { | |
2636 RawTypeParameter* param = TypeParameter::RawCast(obj); | |
2637 param->ptr()->parameterized_class_id_ = | |
2638 Map(param->ptr()->parameterized_class_id_); | |
2639 } else if (obj->IsType()) { | |
2640 RawType* type = Type::RawCast(obj); | |
2641 RawObject* id = type->ptr()->type_class_id_; | |
2642 if (!id->IsHeapObject()) { | |
2643 type->ptr()->type_class_id_ = | |
2644 Smi::New(Map(Smi::Value(Smi::RawCast(id)))); | |
2645 } | |
2646 } else { | |
2647 intptr_t old_cid = obj->GetClassId(); | |
2648 intptr_t new_cid = Map(old_cid); | |
2649 if (old_cid != new_cid) { | |
2650 // Don't touch objects that are unchanged. In particular, Instructions, | |
2651 // which are write-protected. | |
2652 obj->SetClassId(new_cid); | |
2653 } | |
2654 } | |
2655 } | |
2656 | |
2657 private: | |
2658 intptr_t* old_to_new_cids_; | |
2659 }; | |
2660 | |
2661 | |
2662 void Precompiler::RemapClassIds(intptr_t* old_to_new_cid) { | |
2663 // Code, ICData, allocation stubs have now-invalid cids. | |
2664 ClearAllCode(); | |
2665 | |
2666 { | |
2667 HeapIterationScope his; | |
2668 | |
2669 // Update the class table. Do it before rewriting cids in headers, as the | |
2670 // heap walkers load an object's size *after* calling the visitor. | |
2671 I->class_table()->Remap(old_to_new_cid); | |
2672 | |
2673 // Rewrite cids in headers and cids in Classes, Fields, Types and | |
2674 // TypeParameters. | |
2675 { | |
2676 CidRewriteVisitor visitor(old_to_new_cid); | |
2677 I->heap()->VisitObjects(&visitor); | |
2678 } | |
2679 } | |
2680 | |
2681 #if defined(DEBUG) | |
2682 I->class_table()->Validate(); | |
2683 I->heap()->Verify(); | |
2684 #endif | |
2685 } | |
2686 | |
2687 | |
2688 class ClearTypeHashVisitor : public ObjectVisitor { | |
2689 public: | |
2690 explicit ClearTypeHashVisitor(Zone* zone) | |
2691 : type_param_(TypeParameter::Handle(zone)), | |
2692 type_(Type::Handle(zone)), | |
2693 type_args_(TypeArguments::Handle(zone)), | |
2694 bounded_type_(BoundedType::Handle(zone)) {} | |
2695 | |
2696 void VisitObject(RawObject* obj) { | |
2697 if (obj->IsTypeParameter()) { | |
2698 type_param_ ^= obj; | |
2699 type_param_.SetHash(0); | |
2700 } else if (obj->IsType()) { | |
2701 type_ ^= obj; | |
2702 type_.SetHash(0); | |
2703 } else if (obj->IsBoundedType()) { | |
2704 bounded_type_ ^= obj; | |
2705 bounded_type_.SetHash(0); | |
2706 } else if (obj->IsTypeArguments()) { | |
2707 type_args_ ^= obj; | |
2708 type_args_.SetHash(0); | |
2709 } | |
2710 } | |
2711 | |
2712 private: | |
2713 TypeParameter& type_param_; | |
2714 Type& type_; | |
2715 TypeArguments& type_args_; | |
2716 BoundedType& bounded_type_; | |
2717 }; | |
2718 | |
2719 | |
2720 void Precompiler::RehashTypes() { | |
2721 // Clear all cached hash values. | |
2722 { | |
2723 HeapIterationScope his; | |
2724 ClearTypeHashVisitor visitor(Z); | |
2725 I->heap()->VisitObjects(&visitor); | |
2726 } | |
2727 | |
2728 // Rehash the canonical Types table. | |
2729 ObjectStore* object_store = I->object_store(); | |
2730 GrowableObjectArray& types = | |
2731 GrowableObjectArray::Handle(Z, GrowableObjectArray::New()); | |
2732 Array& types_array = Array::Handle(Z); | |
2733 Type& type = Type::Handle(Z); | |
2734 { | |
2735 CanonicalTypeSet types_table(Z, object_store->canonical_types()); | |
2736 types_array = HashTables::ToArray(types_table, false); | |
2737 for (intptr_t i = 0; i < types_array.Length(); i++) { | |
2738 type ^= types_array.At(i); | |
2739 types.Add(type); | |
2740 } | |
2741 types_table.Release(); | |
2742 } | |
2743 | |
2744 intptr_t dict_size = Utils::RoundUpToPowerOfTwo(types.Length() * 4 / 3); | |
2745 types_array = HashTables::New<CanonicalTypeSet>(dict_size, Heap::kOld); | |
2746 CanonicalTypeSet types_table(Z, types_array.raw()); | |
2747 for (intptr_t i = 0; i < types.Length(); i++) { | |
2748 type ^= types.At(i); | |
2749 bool present = types_table.Insert(type); | |
2750 ASSERT(!present || type.IsRecursive()); | |
2751 } | |
2752 object_store->set_canonical_types(types_table.Release()); | |
2753 | |
2754 // Rehash the canonical TypeArguments table. | |
2755 Array& typeargs_array = Array::Handle(Z); | |
2756 GrowableObjectArray& typeargs = | |
2757 GrowableObjectArray::Handle(Z, GrowableObjectArray::New()); | |
2758 TypeArguments& typearg = TypeArguments::Handle(Z); | |
2759 { | |
2760 CanonicalTypeArgumentsSet typeargs_table( | |
2761 Z, object_store->canonical_type_arguments()); | |
2762 typeargs_array = HashTables::ToArray(typeargs_table, false); | |
2763 for (intptr_t i = 0; i < typeargs_array.Length(); i++) { | |
2764 typearg ^= typeargs_array.At(i); | |
2765 typeargs.Add(typearg); | |
2766 } | |
2767 typeargs_table.Release(); | |
2768 } | |
2769 | |
2770 dict_size = Utils::RoundUpToPowerOfTwo(typeargs.Length() * 4 / 3); | |
2771 typeargs_array = | |
2772 HashTables::New<CanonicalTypeArgumentsSet>(dict_size, Heap::kOld); | |
2773 CanonicalTypeArgumentsSet typeargs_table(Z, typeargs_array.raw()); | |
2774 for (intptr_t i = 0; i < typeargs.Length(); i++) { | |
2775 typearg ^= typeargs.At(i); | |
2776 bool present = typeargs_table.Insert(typearg); | |
2777 ASSERT(!present || typearg.IsRecursive()); | |
2778 } | |
2779 object_store->set_canonical_type_arguments(typeargs_table.Release()); | |
2780 } | |
2781 | |
2782 | 2529 |
2783 void Precompiler::VerifyJITFeedback() { | 2530 void Precompiler::VerifyJITFeedback() { |
2784 if (jit_feedback_ == NULL) return; | 2531 if (jit_feedback_ == NULL) return; |
2785 | 2532 |
2786 ParsedJSONString* js_vmversion = jit_feedback_->StringAt("vmVersion"); | 2533 ParsedJSONString* js_vmversion = jit_feedback_->StringAt("vmVersion"); |
2787 if ((js_vmversion == NULL) || | 2534 if ((js_vmversion == NULL) || |
2788 strcmp(js_vmversion->value(), Version::CommitString()) != 0) { | 2535 strcmp(js_vmversion->value(), Version::CommitString()) != 0) { |
2789 THR_Print( | 2536 THR_Print( |
2790 "JIT feedback contains invalid vm version " | 2537 "JIT feedback contains invalid vm version " |
2791 "(saw %s, expected %s).\n", | 2538 "(saw %s, expected %s).\n", |
(...skipping 1013 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3805 | 3552 |
3806 ASSERT(FLAG_precompiled_mode); | 3553 ASSERT(FLAG_precompiled_mode); |
3807 const bool optimized = function.IsOptimizable(); // False for natives. | 3554 const bool optimized = function.IsOptimizable(); // False for natives. |
3808 DartPrecompilationPipeline pipeline(zone, field_type_map); | 3555 DartPrecompilationPipeline pipeline(zone, field_type_map); |
3809 return PrecompileFunctionHelper(precompiler, &pipeline, function, optimized); | 3556 return PrecompileFunctionHelper(precompiler, &pipeline, function, optimized); |
3810 } | 3557 } |
3811 | 3558 |
3812 #endif // DART_PRECOMPILER | 3559 #endif // DART_PRECOMPILER |
3813 | 3560 |
3814 } // namespace dart | 3561 } // namespace dart |
OLD | NEW |