Chromium Code Reviews| Index: runtime/vm/precompiler.cc |
| diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc |
| index a990a0898600e0f84b131676e7b7bdc82bc692e3..dac4d16a850620cc42de4a036e43eb997dce4177 100644 |
| --- a/runtime/vm/precompiler.cc |
| +++ b/runtime/vm/precompiler.cc |
| @@ -4,8 +4,10 @@ |
| #include "vm/precompiler.h" |
| +#include "vm/cha.h" |
| #include "vm/code_patcher.h" |
| #include "vm/compiler.h" |
| +#include "vm/hash_table.h" |
| #include "vm/isolate.h" |
| #include "vm/log.h" |
| #include "vm/longjump.h" |
| @@ -22,6 +24,9 @@ namespace dart { |
| #define Z (zone()) |
| +DEFINE_FLAG(bool, collect_dynamic_function_names, false, |
| + "In precompilation collects all dynamic function names in order to" |
| + " identify unique targets"); |
| DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler."); |
| @@ -97,6 +102,8 @@ void Precompiler::DoCompileAll( |
| // Start with the allocations and invocations that happen from C++. |
| AddRoots(embedder_entry_points); |
| + CollectDynamicFunctionNames(); |
| + |
| // Compile newly found targets and add their callees until we reach a fixed |
| // point. |
| Iterate(); |
| @@ -708,6 +715,121 @@ void Precompiler::CheckForNewDynamicFunctions() { |
| } |
| +class NameFunctionsTraits { |
| + public: |
| + static bool IsMatch(const Object& a, const Object& b) { |
| + return a.IsString() && b.IsString() && |
| + String::Cast(a).Equals(String::Cast(b)); |
| + } |
| + static uword Hash(const Object& obj) { |
| + return String::Cast(obj).Hash(); |
| + } |
| + static RawObject* NewKey(const String& str) { |
| + return str.raw(); |
| + } |
| +}; |
| + |
| +typedef UnorderedHashMap<NameFunctionsTraits> Table; |
| + |
| + |
| +class FunctionsTraits { |
| + public: |
| + static bool IsMatch(const Object& a, const Object& b) { |
| + Zone* zone = Thread::Current()->zone(); |
| + String& a_s = String::Handle(zone); |
| + String& b_s = String::Handle(zone); |
| + a_s = a.IsFunction() ? Function::Cast(a).name() : String::Cast(a).raw(); |
| + b_s = b.IsFunction() ? Function::Cast(b).name() : String::Cast(b).raw(); |
| + ASSERT(a_s.IsSymbol() && b_s.IsSymbol()); |
| + return a_s.raw() == b_s.raw(); |
| + } |
| + static uword Hash(const Object& obj) { |
| + if (obj.IsFunction()) { |
| + return String::Handle(Function::Cast(obj).name()).Hash(); |
| + } else { |
| + ASSERT(String::Cast(obj).IsSymbol()); |
| + return String::Cast(obj).Hash(); |
| + } |
| + } |
| + static RawObject* NewKey(const Function& function) { |
| + return function.raw(); |
| + } |
| +}; |
| + |
| +typedef UnorderedHashSet<FunctionsTraits> UniqueFunctionsSet; |
| + |
| + |
| +void Precompiler::CollectDynamicFunctionNames() { |
| + if (!FLAG_collect_dynamic_function_names) { |
| + return; |
| + } |
| + Library& lib = Library::Handle(Z); |
| + Class& cls = Class::Handle(Z); |
| + Array& functions = Array::Handle(Z); |
| + Function& function = Function::Handle(Z); |
| + String& fname = String::Handle(Z); |
| + Array& farray = Array::Handle(Z); |
| + |
| + Table table(HashTables::New<Table>(100)); |
| + for (intptr_t i = 0; i < libraries_.Length(); i++) { |
| + lib ^= libraries_.At(i); |
| + ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); |
| + while (it.HasNext()) { |
| + cls = it.GetNextClass(); |
| + if (cls.IsDynamicClass()) { |
| + continue; // class 'dynamic' is in the read-only VM isolate. |
| + } |
| + functions = cls.functions(); |
| + for (intptr_t j = 0; j < functions.Length(); j++) { |
| + function ^= functions.At(j); |
| + if (function.IsDynamicFunction()) { |
|
rmacnak
2015/12/03 00:34:34
Regular methods need to be added under their gette
srdjan
2015/12/04 17:14:25
Thanks, good catch. Fixed and also added checks (h
|
| + fname = function.name(); |
| + farray ^= table.InsertNewOrGetValue(fname, Array::empty_array()); |
| + farray = Array::Grow(farray, farray.Length() + 1); |
| + farray.SetAt(farray.Length() - 1, function); |
| + table.UpdateValue(fname, farray); |
| + } |
| + } |
| + } |
| + } |
| + |
| + // Locate all entries with one function only, and which owner is neither |
| + // subclassed nor implemented. |
| + Table::Iterator iter(&table); |
| + String& key = String::Handle(Z); |
| + UniqueFunctionsSet functions_set(HashTables::New<UniqueFunctionsSet>(20)); |
| + while (iter.MoveNext()) { |
| + intptr_t curr_key = iter.Current(); |
| + key ^= table.GetKey(curr_key); |
| + farray ^= table.GetOrNull(key); |
| + ASSERT(!farray.IsNull()); |
| + if (farray.Length() == 1) { |
| + function ^= farray.At(0); |
| + cls = function.Owner(); |
| + if (!CHA::IsImplemented(cls) && !CHA::HasSubclasses(cls)) { |
| + functions_set.Insert(function); |
| + } |
| + } |
| + } |
| + |
| + isolate()->object_store()->set_unique_dynamic_targets( |
| + functions_set.Release()); |
| + table.Release(); |
| +} |
| + |
| + |
| +void Precompiler::GetUniqueDynamicTarget(Isolate* isolate, |
| + const String& fname, |
| + Object* function) { |
| + UniqueFunctionsSet functions_set( |
| + isolate->object_store()->unique_dynamic_targets()); |
| + ASSERT(fname.IsSymbol()); |
| + *function = functions_set.GetOrNull(fname); |
| + ASSERT(functions_set.Release().raw() == |
| + isolate->object_store()->unique_dynamic_targets()); |
| +} |
| + |
| + |
| void Precompiler::DropUncompiledFunctions() { |
| Library& lib = Library::Handle(Z); |
| Class& cls = Class::Handle(Z); |