Chromium Code Reviews| Index: runtime/vm/precompiler.cc |
| diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc |
| index c691a807f2f4ec5b3d8550d57e5b5dd2ffa47adc..d218d7fd306dcfc496bfba0b0cb1a39e14e26ca7 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,10 @@ 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, print_unique_targets, false, "Print unique dynaic targets"); |
| DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler."); |
| @@ -97,6 +103,8 @@ void Precompiler::DoCompileAll( |
| // Start with the allocations and invocations that happen from C++. |
| AddRoots(embedder_entry_points); |
| + CollectDynamicFunctionNames(); |
|
rmacnak
2015/12/04 19:37:23
Nit: Move up to keep AddRoots and Iterate together
srdjan
2015/12/04 20:40:19
Done.
|
| + |
| // Compile newly found targets and add their callees until we reach a fixed |
| // point. |
| Iterate(); |
| @@ -708,6 +716,153 @@ 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; |
| + |
| + |
| +static void AddNameToFunctionsTable(Zone* zone, |
| + Table* table, |
| + const String& fname, |
| + const Function& function) { |
| + Array& farray = Array::Handle(zone); |
| + farray ^= table->InsertNewOrGetValue(fname, Array::empty_array()); |
| + farray = Array::Grow(farray, farray.Length() + 1); |
| + farray.SetAt(farray.Length() - 1, function); |
| + table->UpdateValue(fname, farray); |
| +} |
| + |
| + |
| +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()) { |
| + fname = function.name(); |
| + if (function.IsSetterFunction() || |
| + function.IsImplicitSetterFunction()) { |
| + AddNameToFunctionsTable(zone(), &table, fname, function); |
| + } else if (function.IsGetterFunction() || |
| + function.IsImplicitGetterFunction()) { |
| + // Enter both getter and non getter name. |
| + AddNameToFunctionsTable(zone(), &table, fname, function); |
| + fname = Field::NameFromGetter(fname); |
| + AddNameToFunctionsTable(zone(), &table, fname, function); |
| + } else { |
| + // Regular function. Enter both getter and non getter name. |
| + AddNameToFunctionsTable(zone(), &table, fname, function); |
| + fname = Field::GetterName(fname); |
| + AddNameToFunctionsTable(zone(), &table, fname, function); |
| + } |
| + } |
| + } |
| + } |
| + } |
| + |
| + // Locate all entries with one function only, and which owner is neither |
|
rmacnak
2015/12/04 19:37:23
whose owner
srdjan
2015/12/04 20:40:19
Done.
|
| + // 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); |
| + } |
| + } |
| + } |
| + |
| + if (FLAG_print_unique_targets) { |
| + UniqueFunctionsSet::Iterator unique_iter(&functions_set); |
| + while (unique_iter.MoveNext()) { |
| + intptr_t curr_key = unique_iter.Current(); |
| + function ^= functions_set.GetKey(curr_key); |
| + THR_Print("* %s\n", function.ToQualifiedCString()); |
| + } |
|
rmacnak
2015/12/04 19:37:23
Consider something like
THR_PRINT("%d of %d dynam
srdjan
2015/12/04 20:40:19
Done. s/Size/NumOccupied/
|
| + } |
| + |
| + 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); |