Index: runtime/vm/compilation_trace.cc |
diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc |
index f972dfa1f9d86aadd048a4543f7b1a5ac302014c..2fd2cf0b7b0c079733bfc470adfb2c1177bcc630 100644 |
--- a/runtime/vm/compilation_trace.cc |
+++ b/runtime/vm/compilation_trace.cc |
@@ -22,6 +22,11 @@ CompilationTraceSaver::CompilationTraceSaver(Zone* zone) |
void CompilationTraceSaver::Visit(const Function& function) { |
if (!function.HasCode()) { |
+ return; // Not compiled. |
+ } |
+ if (function.parent_function() != Function::null()) { |
+ // Lookup works poorly for local functions. We compile all local functions |
+ // in a compiled function instead. |
return; |
} |
@@ -52,21 +57,40 @@ CompilationTraceLoader::CompilationTraceLoader(Thread* thread) |
error_(Object::Handle(zone_)) {} |
-RawObject* CompilationTraceLoader::CompileTrace(char* buffer) { |
+static char* FindCharacter(char* str, char goal, char* limit) { |
+ while (str < limit) { |
+ if (*str == goal) { |
+ return str; |
+ } |
+ str++; |
+ } |
+ return NULL; |
+} |
+ |
+ |
+RawObject* CompilationTraceLoader::CompileTrace(uint8_t* buffer, |
+ intptr_t size) { |
// First compile functions named in the trace. |
- char* cursor = buffer; |
- while (cursor != NULL) { |
+ char* cursor = reinterpret_cast<char*>(buffer); |
+ char* limit = cursor + size; |
+ while (cursor < limit) { |
char* uri = cursor; |
- char* comma1 = strchr(uri, ','); |
- if (comma1 == NULL) break; |
+ char* comma1 = FindCharacter(uri, ',', limit); |
+ if (comma1 == NULL) { |
+ break; |
+ } |
*comma1 = 0; |
char* cls_name = comma1 + 1; |
- char* comma2 = strchr(cls_name, ','); |
- if (comma2 == NULL) break; |
+ char* comma2 = FindCharacter(cls_name, ',', limit); |
+ if (comma2 == NULL) { |
+ break; |
+ } |
*comma2 = 0; |
char* func_name = comma2 + 1; |
- char* newline = strchr(func_name, '\n'); |
- if (newline == NULL) break; |
+ char* newline = FindCharacter(func_name, '\n', limit); |
+ if (newline == NULL) { |
+ break; |
+ } |
*newline = 0; |
error_ = CompileTriple(uri, cls_name, func_name); |
if (error_.IsError()) { |
@@ -94,7 +118,8 @@ RawObject* CompilationTraceLoader::CompileTrace(char* buffer) { |
} |
} |
- // Finally, compile closures in all compiled functions. |
+ // Finally, compile closures in all compiled functions. Don't cache the |
+ // length since compiling may append to this list. |
const GrowableObjectArray& closure_functions = GrowableObjectArray::Handle( |
zone_, thread_->isolate()->object_store()->closure_functions()); |
for (intptr_t i = 0; i < closure_functions.Length(); i++) { |
@@ -112,6 +137,16 @@ RawObject* CompilationTraceLoader::CompileTrace(char* buffer) { |
} |
+// Use a fuzzy match to find the right function to compile. This allows a |
+// compilation trace to remain mostly valid in the face of program changes, and |
+// deals with implicit/dispatcher functions that don't have proper names. |
+// - Ignore private name mangling |
+// - If looking for a getter and we only have the corresponding regular method, |
+// compile the regular method, create its implicit closure and compile that. |
+// - If looking for a regular method and we only have the corresponding getter, |
+// compile the getter, create its method extractor and compile that. |
+// - If looking for a getter and we only have a const field, evaluate the const |
+// field. |
RawObject* CompilationTraceLoader::CompileTriple(const char* uri_cstr, |
const char* cls_cstr, |
const char* func_cstr) { |
@@ -158,8 +193,8 @@ RawObject* CompilationTraceLoader::CompileTriple(const char* uri_cstr, |
function_ = cls_.LookupFunctionAllowPrivate(function_name_); |
field_ = cls_.LookupFieldAllowPrivate(function_name_); |
- if (field_.IsNull() && is_getter) { |
- // Maybe this is a tear off. |
+ if (function_.IsNull() && is_getter) { |
+ // Maybe this was a tear off. |
add_closure = true; |
function_name2_ = Field::NameFromGetter(function_name_); |
function_ = cls_.LookupFunctionAllowPrivate(function_name2_); |