diff options
author | Sebastien Hertz <shertz@google.com> | 2014-01-15 10:20:56 +0100 |
---|---|---|
committer | Sebastien Hertz <shertz@google.com> | 2014-02-17 11:32:15 +0100 |
commit | d2fe10a3a34af171bf1631219cd2d6ff6b7778b5 (patch) | |
tree | b6b7eb8eba23a5c2723518da99c03bf47b97f58a /runtime/intern_table.cc | |
parent | 5a3f55ad9519e87c0d3bbddaf3d8a186a887a79b (diff) | |
download | art-d2fe10a3a34af171bf1631219cd2d6ff6b7778b5.zip art-d2fe10a3a34af171bf1631219cd2d6ff6b7778b5.tar.gz art-d2fe10a3a34af171bf1631219cd2d6ff6b7778b5.tar.bz2 |
Remove blacklist
Removes the class initialization blacklist and use transaction to detect and
revert class initialization attempting to invoke native method. This only
concerns class initialization happening at compilation time when generating an
image (like boot.art for the system).
In transactional mode, we log every object's field assignment and array update.
Therefore we're able to abort a transaction to restore values of fields and
array as they were before the transaction starts. We also log changes to the
intern string table so we can restore its state prior to transaction start.
Since transactional mode only happens at compilation time, we don't need to log
all these changes at runtime. In order to reduce the overhead of testing if
transactional mode is on/off, we templatize interfaces of mirror::Object and
mirror::Array, respectively responsible for setting a field and setting an
array element.
For various reasons, we skip some specific fields from transaction:
- Object's class and array's length must remain unchanged so garbage collector
can compute object's size.
- Immutable fields only set during class loading: list of fields, method,
dex caches, vtables, ... as all classes have been loaded and verified before a
transaction occurs.
- Object's monitor for performance reason.
Before generating the image, we browse the heap to collect objects that need to
be written into it. Since the heap may still holds references to unreachable
objects due to aborted transactions, we trigger one collection at the end of
the class preinitialization phase.
Since the transaction is held by the runtime and all compilation threads share
the same runtime, we need to ensure only one compilation thread has exclusive
access to the runtime. To workaround this issue, we force class initialization
phase to run with only one thread. Note this is only done when generating image
so application compilation is not impacted. This issue will be addressed in a
separate CL.
Bug: 9676614
Change-Id: I221910a9183a5ba6c2b99a277f5a5a68bc69b5f9
Diffstat (limited to 'runtime/intern_table.cc')
-rw-r--r-- | runtime/intern_table.cc | 83 |
1 files changed, 62 insertions, 21 deletions
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc index 5693747..cc49d67 100644 --- a/runtime/intern_table.cc +++ b/runtime/intern_table.cc @@ -28,24 +28,24 @@ namespace art { InternTable::InternTable() - : intern_table_lock_("InternTable lock"), is_dirty_(false), allow_new_interns_(true), - new_intern_condition_("New intern condition", intern_table_lock_) { + : is_dirty_(false), allow_new_interns_(true), + new_intern_condition_("New intern condition", *Locks::intern_table_lock_) { } size_t InternTable::Size() const { - MutexLock mu(Thread::Current(), intern_table_lock_); + MutexLock mu(Thread::Current(), *Locks::intern_table_lock_); return strong_interns_.size() + weak_interns_.size(); } void InternTable::DumpForSigQuit(std::ostream& os) const { - MutexLock mu(Thread::Current(), intern_table_lock_); + MutexLock mu(Thread::Current(), *Locks::intern_table_lock_); os << "Intern table: " << strong_interns_.size() << " strong; " << weak_interns_.size() << " weak\n"; } void InternTable::VisitRoots(RootCallback* callback, void* arg, bool only_dirty, bool clean_dirty) { - MutexLock mu(Thread::Current(), intern_table_lock_); + MutexLock mu(Thread::Current(), *Locks::intern_table_lock_); if (!only_dirty || is_dirty_) { for (auto& strong_intern : strong_interns_) { strong_intern.second = @@ -61,7 +61,7 @@ void InternTable::VisitRoots(RootCallback* callback, void* arg, } mirror::String* InternTable::Lookup(Table& table, mirror::String* s, uint32_t hash_code) { - intern_table_lock_.AssertHeld(Thread::Current()); + Locks::intern_table_lock_->AssertHeld(Thread::Current()); for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { mirror::String* existing_string = it->second; if (existing_string->Equals(s)) { @@ -71,15 +71,38 @@ mirror::String* InternTable::Lookup(Table& table, mirror::String* s, uint32_t ha return NULL; } +mirror::String* InternTable::InsertStrong(mirror::String* s, uint32_t hash_code) { + Runtime* runtime = Runtime::Current(); + if (runtime->IsActiveTransaction()) { + runtime->RecordStrongStringInsertion(s, hash_code); + } + return Insert(strong_interns_, s, hash_code); +} + +mirror::String* InternTable::InsertWeak(mirror::String* s, uint32_t hash_code) { + Runtime* runtime = Runtime::Current(); + if (runtime->IsActiveTransaction()) { + runtime->RecordWeakStringInsertion(s, hash_code); + } + return Insert(weak_interns_, s, hash_code); +} + mirror::String* InternTable::Insert(Table& table, mirror::String* s, uint32_t hash_code) { - intern_table_lock_.AssertHeld(Thread::Current()); + Locks::intern_table_lock_->AssertHeld(Thread::Current()); table.insert(std::make_pair(hash_code, s)); return s; } -void InternTable::Remove(Table& table, const mirror::String* s, - uint32_t hash_code) { - intern_table_lock_.AssertHeld(Thread::Current()); +void InternTable::RemoveWeak(mirror::String* s, uint32_t hash_code) { + Runtime* runtime = Runtime::Current(); + if (runtime->IsActiveTransaction()) { + runtime->RecordWeakStringRemoval(s, hash_code); + } + Remove(weak_interns_, s, hash_code); +} + +void InternTable::Remove(Table& table, mirror::String* s, uint32_t hash_code) { + Locks::intern_table_lock_->AssertHeld(Thread::Current()); for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { if (it->second == s) { table.erase(it); @@ -88,6 +111,24 @@ void InternTable::Remove(Table& table, const mirror::String* s, } } +// Insert/remove methods used to undo changes made during an aborted transaction. +mirror::String* InternTable::InsertStrongFromTransaction(mirror::String* s, uint32_t hash_code) { + DCHECK(!Runtime::Current()->IsActiveTransaction()); + return InsertStrong(s, hash_code); +} +mirror::String* InternTable::InsertWeakFromTransaction(mirror::String* s, uint32_t hash_code) { + DCHECK(!Runtime::Current()->IsActiveTransaction()); + return InsertWeak(s, hash_code); +} +void InternTable::RemoveStrongFromTransaction(mirror::String* s, uint32_t hash_code) { + DCHECK(!Runtime::Current()->IsActiveTransaction()); + Remove(strong_interns_, s, hash_code); +} +void InternTable::RemoveWeakFromTransaction(mirror::String* s, uint32_t hash_code) { + DCHECK(!Runtime::Current()->IsActiveTransaction()); + Remove(weak_interns_, s, hash_code); +} + static mirror::String* LookupStringFromImage(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace(); @@ -115,20 +156,20 @@ static mirror::String* LookupStringFromImage(mirror::String* s) void InternTable::AllowNewInterns() { Thread* self = Thread::Current(); - MutexLock mu(self, intern_table_lock_); + MutexLock mu(self, *Locks::intern_table_lock_); allow_new_interns_ = true; new_intern_condition_.Broadcast(self); } void InternTable::DisallowNewInterns() { Thread* self = Thread::Current(); - MutexLock mu(self, intern_table_lock_); + MutexLock mu(self, *Locks::intern_table_lock_); allow_new_interns_ = false; } mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { Thread* self = Thread::Current(); - MutexLock mu(self, intern_table_lock_); + MutexLock mu(self, *Locks::intern_table_lock_); DCHECK(s != NULL); uint32_t hash_code = s->GetHashCode(); @@ -150,20 +191,20 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { // Check the image for a match. mirror::String* image = LookupStringFromImage(s); if (image != NULL) { - return Insert(strong_interns_, image, hash_code); + return InsertStrong(image, hash_code); } // There is no match in the strong table, check the weak table. mirror::String* weak = Lookup(weak_interns_, s, hash_code); if (weak != NULL) { // A match was found in the weak table. Promote to the strong table. - Remove(weak_interns_, weak, hash_code); - return Insert(strong_interns_, weak, hash_code); + RemoveWeak(weak, hash_code); + return InsertStrong(weak, hash_code); } // No match in the strong table or the weak table. Insert into the strong // table. - return Insert(strong_interns_, s, hash_code); + return InsertStrong(s, hash_code); } // Check the strong table for a match. @@ -174,7 +215,7 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { // Check the image for a match. mirror::String* image = LookupStringFromImage(s); if (image != NULL) { - return Insert(weak_interns_, image, hash_code); + return InsertWeak(image, hash_code); } // Check the weak table for a match. mirror::String* weak = Lookup(weak_interns_, s, hash_code); @@ -182,7 +223,7 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { return weak; } // Insert into the weak table. - return Insert(weak_interns_, s, hash_code); + return InsertWeak(s, hash_code); } mirror::String* InternTable::InternStrong(int32_t utf16_length, @@ -211,13 +252,13 @@ mirror::String* InternTable::InternWeak(mirror::String* s) { } bool InternTable::ContainsWeak(mirror::String* s) { - MutexLock mu(Thread::Current(), intern_table_lock_); + MutexLock mu(Thread::Current(), *Locks::intern_table_lock_); const mirror::String* found = Lookup(weak_interns_, s, s->GetHashCode()); return found == s; } void InternTable::SweepInternTableWeaks(IsMarkedCallback* callback, void* arg) { - MutexLock mu(Thread::Current(), intern_table_lock_); + MutexLock mu(Thread::Current(), *Locks::intern_table_lock_); for (auto it = weak_interns_.begin(), end = weak_interns_.end(); it != end;) { mirror::Object* object = it->second; mirror::Object* new_object = callback(object, arg); |