Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Unified Diff: runtime/vm/precompiler.cc

Issue 1496713002: --collect_dynamic_function_names (default false): find unique virtual function names and use them t… (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: g Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/precompiler.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « runtime/vm/precompiler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698