OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/class_finalizer.h" | 5 #include "vm/class_finalizer.h" |
6 | 6 |
7 #include "vm/code_generator.h" | 7 #include "vm/code_generator.h" |
8 #include "vm/flags.h" | 8 #include "vm/flags.h" |
| 9 #include "vm/hash_table.h" |
9 #include "vm/heap.h" | 10 #include "vm/heap.h" |
10 #include "vm/isolate.h" | 11 #include "vm/isolate.h" |
11 #include "vm/longjump.h" | 12 #include "vm/longjump.h" |
12 #include "vm/log.h" | 13 #include "vm/log.h" |
13 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 15 #include "vm/program_visitor.h" |
14 #include "vm/symbols.h" | 16 #include "vm/symbols.h" |
15 #include "vm/timeline.h" | 17 #include "vm/timeline.h" |
| 18 #include "vm/type_table.h" |
16 | 19 |
17 namespace dart { | 20 namespace dart { |
18 | 21 |
19 DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes."); | 22 DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes."); |
20 DEFINE_FLAG(bool, reify, true, "Reify type arguments of generic types."); | 23 DEFINE_FLAG(bool, reify, true, "Reify type arguments of generic types."); |
21 DEFINE_FLAG(bool, trace_class_finalization, false, "Trace class finalization."); | 24 DEFINE_FLAG(bool, trace_class_finalization, false, "Trace class finalization."); |
22 DEFINE_FLAG(bool, trace_type_finalization, false, "Trace type finalization."); | 25 DEFINE_FLAG(bool, trace_type_finalization, false, "Trace type finalization."); |
23 | 26 |
24 | 27 |
25 bool ClassFinalizer::AllClassesFinalized() { | 28 bool ClassFinalizer::AllClassesFinalized() { |
(...skipping 3408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3434 fields_array ^= cls.fields(); | 3437 fields_array ^= cls.fields(); |
3435 ASSERT(fields_array.Length() == ByteBuffer::NumberOfFields()); | 3438 ASSERT(fields_array.Length() == ByteBuffer::NumberOfFields()); |
3436 field ^= fields_array.At(0); | 3439 field ^= fields_array.At(0); |
3437 ASSERT(field.Offset() == ByteBuffer::data_offset()); | 3440 ASSERT(field.Offset() == ByteBuffer::data_offset()); |
3438 name ^= field.name(); | 3441 name ^= field.name(); |
3439 expected_name ^= String::New("_data"); | 3442 expected_name ^= String::New("_data"); |
3440 ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name)); | 3443 ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name)); |
3441 #endif | 3444 #endif |
3442 } | 3445 } |
3443 | 3446 |
| 3447 |
| 3448 void ClassFinalizer::SortClasses() { |
| 3449 Thread* T = Thread::Current(); |
| 3450 Zone* Z = T->zone(); |
| 3451 Isolate* I = T->isolate(); |
| 3452 ClassTable* table = I->class_table(); |
| 3453 intptr_t num_cids = table->NumCids(); |
| 3454 intptr_t* old_to_new_cid = new intptr_t[num_cids]; |
| 3455 for (intptr_t cid = 0; cid < kNumPredefinedCids; cid++) { |
| 3456 old_to_new_cid[cid] = cid; // The predefined classes cannot change cids. |
| 3457 } |
| 3458 for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) { |
| 3459 old_to_new_cid[cid] = -1; |
| 3460 } |
| 3461 |
| 3462 intptr_t next_new_cid = kNumPredefinedCids; |
| 3463 GrowableArray<intptr_t> dfs_stack; |
| 3464 Class& cls = Class::Handle(Z); |
| 3465 GrowableObjectArray& subclasses = GrowableObjectArray::Handle(Z); |
| 3466 |
| 3467 // Object doesn't use its subclasses list. |
| 3468 for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) { |
| 3469 if (!table->HasValidClassAt(cid)) { |
| 3470 continue; |
| 3471 } |
| 3472 cls = table->At(cid); |
| 3473 if (cls.is_patch()) { |
| 3474 continue; |
| 3475 } |
| 3476 if (cls.SuperClass() == I->object_store()->object_class()) { |
| 3477 dfs_stack.Add(cid); |
| 3478 } |
| 3479 } |
| 3480 |
| 3481 while (dfs_stack.length() > 0) { |
| 3482 intptr_t cid = dfs_stack.RemoveLast(); |
| 3483 ASSERT(table->HasValidClassAt(cid)); |
| 3484 cls = table->At(cid); |
| 3485 ASSERT(!cls.IsNull()); |
| 3486 if (old_to_new_cid[cid] == -1) { |
| 3487 old_to_new_cid[cid] = next_new_cid++; |
| 3488 if (FLAG_trace_class_finalization) { |
| 3489 THR_Print("%" Pd ": %s, was %" Pd "\n", old_to_new_cid[cid], |
| 3490 cls.ToCString(), cid); |
| 3491 } |
| 3492 } |
| 3493 subclasses = cls.direct_subclasses(); |
| 3494 if (!subclasses.IsNull()) { |
| 3495 for (intptr_t i = 0; i < subclasses.Length(); i++) { |
| 3496 cls ^= subclasses.At(i); |
| 3497 ASSERT(!cls.IsNull()); |
| 3498 dfs_stack.Add(cls.id()); |
| 3499 } |
| 3500 } |
| 3501 } |
| 3502 |
| 3503 // Top-level classes, typedefs, patch classes, etc. |
| 3504 for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) { |
| 3505 if (old_to_new_cid[cid] == -1) { |
| 3506 old_to_new_cid[cid] = next_new_cid++; |
| 3507 if (FLAG_trace_class_finalization && table->HasValidClassAt(cid)) { |
| 3508 cls = table->At(cid); |
| 3509 THR_Print("%" Pd ": %s, was %" Pd "\n", old_to_new_cid[cid], |
| 3510 cls.ToCString(), cid); |
| 3511 } |
| 3512 } |
| 3513 } |
| 3514 ASSERT(next_new_cid == num_cids); |
| 3515 |
| 3516 RemapClassIds(old_to_new_cid); |
| 3517 delete[] old_to_new_cid; |
| 3518 RehashTypes(); // Types use cid's as part of their hashes. |
| 3519 } |
| 3520 |
| 3521 |
| 3522 class CidRewriteVisitor : public ObjectVisitor { |
| 3523 public: |
| 3524 explicit CidRewriteVisitor(intptr_t* old_to_new_cids) |
| 3525 : old_to_new_cids_(old_to_new_cids) {} |
| 3526 |
| 3527 intptr_t Map(intptr_t cid) { |
| 3528 ASSERT(cid != -1); |
| 3529 return old_to_new_cids_[cid]; |
| 3530 } |
| 3531 |
| 3532 void VisitObject(RawObject* obj) { |
| 3533 if (obj->IsClass()) { |
| 3534 RawClass* cls = Class::RawCast(obj); |
| 3535 cls->ptr()->id_ = Map(cls->ptr()->id_); |
| 3536 } else if (obj->IsField()) { |
| 3537 RawField* field = Field::RawCast(obj); |
| 3538 field->ptr()->guarded_cid_ = Map(field->ptr()->guarded_cid_); |
| 3539 field->ptr()->is_nullable_ = Map(field->ptr()->is_nullable_); |
| 3540 } else if (obj->IsTypeParameter()) { |
| 3541 RawTypeParameter* param = TypeParameter::RawCast(obj); |
| 3542 param->ptr()->parameterized_class_id_ = |
| 3543 Map(param->ptr()->parameterized_class_id_); |
| 3544 } else if (obj->IsType()) { |
| 3545 RawType* type = Type::RawCast(obj); |
| 3546 RawObject* id = type->ptr()->type_class_id_; |
| 3547 if (!id->IsHeapObject()) { |
| 3548 type->ptr()->type_class_id_ = |
| 3549 Smi::New(Map(Smi::Value(Smi::RawCast(id)))); |
| 3550 } |
| 3551 } else { |
| 3552 intptr_t old_cid = obj->GetClassId(); |
| 3553 intptr_t new_cid = Map(old_cid); |
| 3554 if (old_cid != new_cid) { |
| 3555 // Don't touch objects that are unchanged. In particular, Instructions, |
| 3556 // which are write-protected. |
| 3557 obj->SetClassId(new_cid); |
| 3558 } |
| 3559 } |
| 3560 } |
| 3561 |
| 3562 private: |
| 3563 intptr_t* old_to_new_cids_; |
| 3564 }; |
| 3565 |
| 3566 |
| 3567 void ClassFinalizer::RemapClassIds(intptr_t* old_to_new_cid) { |
| 3568 Isolate* I = Thread::Current()->isolate(); |
| 3569 |
| 3570 // Code, ICData, allocation stubs have now-invalid cids. |
| 3571 ClearAllCode(); |
| 3572 |
| 3573 { |
| 3574 HeapIterationScope his; |
| 3575 I->set_remapping_cids(true); |
| 3576 |
| 3577 // Update the class table. Do it before rewriting cids in headers, as the |
| 3578 // heap walkers load an object's size *after* calling the visitor. |
| 3579 I->class_table()->Remap(old_to_new_cid); |
| 3580 |
| 3581 // Rewrite cids in headers and cids in Classes, Fields, Types and |
| 3582 // TypeParameters. |
| 3583 { |
| 3584 CidRewriteVisitor visitor(old_to_new_cid); |
| 3585 I->heap()->VisitObjects(&visitor); |
| 3586 } |
| 3587 I->set_remapping_cids(false); |
| 3588 } |
| 3589 |
| 3590 #if defined(DEBUG) |
| 3591 I->class_table()->Validate(); |
| 3592 I->heap()->Verify(); |
| 3593 #endif |
| 3594 } |
| 3595 |
| 3596 |
| 3597 class ClearTypeHashVisitor : public ObjectVisitor { |
| 3598 public: |
| 3599 explicit ClearTypeHashVisitor(Zone* zone) |
| 3600 : type_param_(TypeParameter::Handle(zone)), |
| 3601 type_(Type::Handle(zone)), |
| 3602 type_args_(TypeArguments::Handle(zone)), |
| 3603 bounded_type_(BoundedType::Handle(zone)) {} |
| 3604 |
| 3605 void VisitObject(RawObject* obj) { |
| 3606 if (obj->IsTypeParameter()) { |
| 3607 type_param_ ^= obj; |
| 3608 type_param_.SetHash(0); |
| 3609 } else if (obj->IsType()) { |
| 3610 type_ ^= obj; |
| 3611 type_.SetHash(0); |
| 3612 } else if (obj->IsBoundedType()) { |
| 3613 bounded_type_ ^= obj; |
| 3614 bounded_type_.SetHash(0); |
| 3615 } else if (obj->IsTypeArguments()) { |
| 3616 type_args_ ^= obj; |
| 3617 type_args_.SetHash(0); |
| 3618 } |
| 3619 } |
| 3620 |
| 3621 private: |
| 3622 TypeParameter& type_param_; |
| 3623 Type& type_; |
| 3624 TypeArguments& type_args_; |
| 3625 BoundedType& bounded_type_; |
| 3626 }; |
| 3627 |
| 3628 |
| 3629 void ClassFinalizer::RehashTypes() { |
| 3630 Thread* T = Thread::Current(); |
| 3631 Zone* Z = T->zone(); |
| 3632 Isolate* I = T->isolate(); |
| 3633 |
| 3634 // Clear all cached hash values. |
| 3635 { |
| 3636 HeapIterationScope his; |
| 3637 ClearTypeHashVisitor visitor(Z); |
| 3638 I->heap()->VisitObjects(&visitor); |
| 3639 } |
| 3640 |
| 3641 // Rehash the canonical Types table. |
| 3642 ObjectStore* object_store = I->object_store(); |
| 3643 GrowableObjectArray& types = |
| 3644 GrowableObjectArray::Handle(Z, GrowableObjectArray::New()); |
| 3645 Array& types_array = Array::Handle(Z); |
| 3646 Type& type = Type::Handle(Z); |
| 3647 { |
| 3648 CanonicalTypeSet types_table(Z, object_store->canonical_types()); |
| 3649 types_array = HashTables::ToArray(types_table, false); |
| 3650 for (intptr_t i = 0; i < types_array.Length(); i++) { |
| 3651 type ^= types_array.At(i); |
| 3652 types.Add(type); |
| 3653 } |
| 3654 types_table.Release(); |
| 3655 } |
| 3656 |
| 3657 intptr_t dict_size = Utils::RoundUpToPowerOfTwo(types.Length() * 4 / 3); |
| 3658 types_array = HashTables::New<CanonicalTypeSet>(dict_size, Heap::kOld); |
| 3659 CanonicalTypeSet types_table(Z, types_array.raw()); |
| 3660 for (intptr_t i = 0; i < types.Length(); i++) { |
| 3661 type ^= types.At(i); |
| 3662 bool present = types_table.Insert(type); |
| 3663 ASSERT(!present || type.IsRecursive()); |
| 3664 } |
| 3665 object_store->set_canonical_types(types_table.Release()); |
| 3666 |
| 3667 // Rehash the canonical TypeArguments table. |
| 3668 Array& typeargs_array = Array::Handle(Z); |
| 3669 GrowableObjectArray& typeargs = |
| 3670 GrowableObjectArray::Handle(Z, GrowableObjectArray::New()); |
| 3671 TypeArguments& typearg = TypeArguments::Handle(Z); |
| 3672 { |
| 3673 CanonicalTypeArgumentsSet typeargs_table( |
| 3674 Z, object_store->canonical_type_arguments()); |
| 3675 typeargs_array = HashTables::ToArray(typeargs_table, false); |
| 3676 for (intptr_t i = 0; i < typeargs_array.Length(); i++) { |
| 3677 typearg ^= typeargs_array.At(i); |
| 3678 typeargs.Add(typearg); |
| 3679 } |
| 3680 typeargs_table.Release(); |
| 3681 } |
| 3682 |
| 3683 dict_size = Utils::RoundUpToPowerOfTwo(typeargs.Length() * 4 / 3); |
| 3684 typeargs_array = |
| 3685 HashTables::New<CanonicalTypeArgumentsSet>(dict_size, Heap::kOld); |
| 3686 CanonicalTypeArgumentsSet typeargs_table(Z, typeargs_array.raw()); |
| 3687 for (intptr_t i = 0; i < typeargs.Length(); i++) { |
| 3688 typearg ^= typeargs.At(i); |
| 3689 bool present = typeargs_table.Insert(typearg); |
| 3690 ASSERT(!present || typearg.IsRecursive()); |
| 3691 } |
| 3692 object_store->set_canonical_type_arguments(typeargs_table.Release()); |
| 3693 } |
| 3694 |
| 3695 |
| 3696 void ClassFinalizer::ClearAllCode() { |
| 3697 class ClearCodeFunctionVisitor : public FunctionVisitor { |
| 3698 void Visit(const Function& function) { |
| 3699 function.ClearCode(); |
| 3700 function.ClearICDataArray(); |
| 3701 } |
| 3702 }; |
| 3703 ClearCodeFunctionVisitor function_visitor; |
| 3704 ProgramVisitor::VisitFunctions(&function_visitor); |
| 3705 |
| 3706 class ClearCodeClassVisitor : public ClassVisitor { |
| 3707 void Visit(const Class& cls) { cls.DisableAllocationStub(); } |
| 3708 }; |
| 3709 ClearCodeClassVisitor class_visitor; |
| 3710 ProgramVisitor::VisitClasses(&class_visitor); |
| 3711 } |
| 3712 |
3444 } // namespace dart | 3713 } // namespace dart |
OLD | NEW |