Index: runtime/vm/dart_api_impl.cc |
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc |
index fd6ff190f364a23ea0dca9ab485680cb8e79b777..dc37989111bbf679ddc4e4399f44ba57490c11b0 100644 |
--- a/runtime/vm/dart_api_impl.cc |
+++ b/runtime/vm/dart_api_impl.cc |
@@ -23,25 +23,25 @@ |
#include "vm/exceptions.h" |
#include "vm/flags.h" |
#include "vm/growable_array.h" |
-#include "vm/lockers.h" |
#include "vm/isolate_reload.h" |
#include "vm/kernel_isolate.h" |
+#include "vm/lockers.h" |
#include "vm/message.h" |
#include "vm/message_handler.h" |
#include "vm/native_entry.h" |
#include "vm/object.h" |
#include "vm/object_store.h" |
-#include "vm/os_thread.h" |
#include "vm/os.h" |
+#include "vm/os_thread.h" |
#include "vm/port.h" |
#include "vm/precompiler.h" |
#include "vm/profiler.h" |
#include "vm/program_visitor.h" |
#include "vm/resolver.h" |
#include "vm/reusable_handles.h" |
+#include "vm/service.h" |
#include "vm/service_event.h" |
#include "vm/service_isolate.h" |
-#include "vm/service.h" |
#include "vm/stack_frame.h" |
#include "vm/symbols.h" |
#include "vm/tags.h" |
@@ -52,6 +52,7 @@ |
#include "vm/uri.h" |
#include "vm/verifier.h" |
#include "vm/version.h" |
+#include "vm/zone_text_buffer.h" |
namespace dart { |
@@ -6488,6 +6489,264 @@ DART_EXPORT void Dart_SetThreadName(const char* name) { |
} |
+class CompilationTraceSaver : public FunctionVisitor { |
zra
2017/06/05 22:08:57
Since this source file is already 7k+ lines, consi
rmacnak
2017/06/05 23:14:08
Done.
|
+ public: |
+ explicit CompilationTraceSaver(Zone* zone) |
+ : buf_(zone, 4 * KB), |
+ func_name_(String::Handle(zone)), |
+ cls_(Class::Handle(zone)), |
+ cls_name_(String::Handle(zone)), |
+ lib_(Library::Handle(zone)), |
+ uri_(String::Handle(zone)) {} |
+ |
+ void Visit(const Function& function) { |
+ if (!function.HasCode()) return; |
zra
2017/06/05 22:08:57
curly braces.
rmacnak
2017/06/05 23:14:08
Done.
|
+ |
+ func_name_ = function.name(); |
+ func_name_ = String::RemovePrivateKey(func_name_); |
+ cls_ = function.Owner(); |
+ cls_name_ = cls_.Name(); |
+ cls_name_ = String::RemovePrivateKey(cls_name_); |
+ lib_ = cls_.library(); |
+ uri_ = lib_.url(); |
+ buf_.Printf("%s,%s,%s\n", uri_.ToCString(), cls_name_.ToCString(), |
+ func_name_.ToCString()); |
+ } |
+ |
+ void StealBuffer(uint8_t** buffer, intptr_t* buffer_length) { |
+ *buffer = reinterpret_cast<uint8_t*>(buf_.buffer()); |
+ *buffer_length = buf_.length() + 1; // Include terminating NUL. |
+ } |
+ |
+ private: |
+ ZoneTextBuffer buf_; |
+ String& func_name_; |
+ Class& cls_; |
+ String& cls_name_; |
+ Library& lib_; |
+ String& uri_; |
+}; |
+ |
+ |
+DART_EXPORT |
+Dart_Handle Dart_SaveCompilationTrace(uint8_t** buffer, |
+ intptr_t* buffer_length) { |
+ API_TIMELINE_DURATION; |
+ Thread* thread = Thread::Current(); |
+ DARTSCOPE(thread); |
+ CHECK_NULL(buffer); |
+ CHECK_NULL(buffer_length); |
+ CompilationTraceSaver saver(thread->zone()); |
+ ProgramVisitor::VisitFunctions(&saver); |
+ saver.StealBuffer(buffer, buffer_length); |
+ return Api::Success(); |
+} |
+ |
+ |
+class CompilationTraceLoader : public ValueObject { |
+ public: |
+ explicit CompilationTraceLoader(Thread* thread) |
+ : thread_(thread), |
+ zone_(thread->zone()), |
+ uri_(String::Handle(zone_)), |
+ class_name_(String::Handle(zone_)), |
+ function_name_(String::Handle(zone_)), |
+ function_name2_(String::Handle(zone_)), |
+ lib_(Library::Handle(zone_)), |
+ cls_(Class::Handle(zone_)), |
+ function_(Function::Handle(zone_)), |
+ function2_(Function::Handle(zone_)), |
+ field_(Field::Handle(zone_)), |
+ error_(Object::Handle(zone_)) {} |
+ |
+ RawObject* CompileTrace(char* buffer) { |
+ // First compile function named in the trace. |
zra
2017/06/05 22:08:57
functions
rmacnak
2017/06/05 23:14:08
Done.
|
+ char* cursor = buffer; |
+ while (cursor != NULL) { |
+ char* uri = cursor; |
+ char* comma1 = strchr(uri, ','); |
+ if (comma1 == NULL) break; |
+ *comma1 = 0; |
+ char* cls_name = comma1 + 1; |
+ char* comma2 = strchr(cls_name, ','); |
+ if (comma2 == NULL) break; |
+ *comma2 = 0; |
+ char* func_name = comma2 + 1; |
+ char* newline = strchr(func_name, '\n'); |
+ if (newline == NULL) break; |
+ *newline = 0; |
+ error_ = CompileTriple(uri, cls_name, func_name); |
+ if (error_.IsError()) { |
+ return error_.raw(); |
+ } |
+ cursor = newline + 1; |
+ } |
+ |
+ // Next, compile common dispatchers. This aren't found with the normal |
zra
2017/06/05 22:08:57
These aren't
rmacnak
2017/06/05 23:14:08
Done.
|
+ // lookup above because they have irregular lookup that depends on the |
+ // arguments descriptor (e.g. call() versus call(x)). |
+ const Class& closure_class = Class::Handle( |
+ zone_, thread_->isolate()->object_store()->closure_class()); |
+ Array& arguments_descriptor = Array::Handle(zone_); |
+ Function& dispatcher = Function::Handle(zone_); |
+ for (intptr_t argc = 1; argc <= 4; argc++) { |
+ const intptr_t kTypeArgsLen = 0; |
+ arguments_descriptor = ArgumentsDescriptor::New(kTypeArgsLen, argc); |
+ dispatcher = closure_class.GetInvocationDispatcher( |
+ Symbols::Call(), arguments_descriptor, |
+ RawFunction::kInvokeFieldDispatcher, true /* create_if_absent */); |
+ error_ = CompileFunction(dispatcher); |
+ if (error_.IsError()) { |
+ return error_.raw(); |
+ } |
+ } |
+ |
+ // Finally, compile closures in all compiled functions. |
+ const GrowableObjectArray& closure_functions = GrowableObjectArray::Handle( |
+ zone_, thread_->isolate()->object_store()->closure_functions()); |
+ for (intptr_t i = 0; i < closure_functions.Length(); i++) { |
+ function_ ^= closure_functions.At(i); |
+ function2_ = function_.parent_function(); |
+ if (function2_.HasCode()) { |
+ error_ = CompileFunction(function_); |
+ if (error_.IsError()) { |
+ return error_.raw(); |
+ } |
+ } |
+ } |
+ |
+ return Object::null(); |
+ } |
+ |
+ private: |
+ RawObject* CompileTriple(const char* uri_cstr, |
+ const char* cls_cstr, |
+ const char* func_cstr) { |
+ uri_ = Symbols::New(thread_, uri_cstr); |
+ class_name_ = Symbols::New(thread_, cls_cstr); |
+ function_name_ = Symbols::New(thread_, func_cstr); |
+ |
+ if (function_name_.Equals("_getMainClosure")) { |
+ // The scheme for invoking main relies on compiling _getMainClosure after |
+ // synthetically importing the root library. |
+ return Object::null(); |
+ } |
+ |
+ lib_ = Library::LookupLibrary(thread_, uri_); |
+ if (lib_.IsNull()) { |
+ // Missing library. |
+ return Object::null(); |
+ } |
+ |
+ bool is_getter = Field::IsGetterName(function_name_); |
+ bool add_closure = false; |
+ |
+ if (class_name_.Equals(Symbols::TopLevel())) { |
+ function_ = lib_.LookupFunctionAllowPrivate(function_name_); |
+ field_ = lib_.LookupFieldAllowPrivate(function_name_); |
+ if (function_.IsNull() && is_getter) { |
+ // Maybe this was a tear off. |
+ add_closure = true; |
+ function_name2_ = Field::NameFromGetter(function_name_); |
+ function_ = lib_.LookupFunctionAllowPrivate(function_name2_); |
+ field_ = lib_.LookupFieldAllowPrivate(function_name2_); |
+ } |
+ } else { |
+ cls_ = lib_.SlowLookupClassAllowMultiPartPrivate(class_name_); |
+ if (cls_.IsNull()) { |
+ // Missing class. |
+ return Object::null(); |
+ } |
+ |
+ error_ = cls_.EnsureIsFinalized(thread_); |
+ if (error_.IsError()) { |
+ return error_.raw(); |
+ } |
+ |
+ function_ = cls_.LookupFunctionAllowPrivate(function_name_); |
+ field_ = cls_.LookupFieldAllowPrivate(function_name_); |
+ if (field_.IsNull() && is_getter) { |
+ // Maybe this is a tear off. |
+ add_closure = true; |
+ function_name2_ = Field::NameFromGetter(function_name_); |
+ function_ = cls_.LookupFunctionAllowPrivate(function_name2_); |
+ field_ = cls_.LookupFieldAllowPrivate(function_name2_); |
+ if (!function_.IsNull() && !function_.is_static()) { |
+ // Maybe this was a method extractor. |
+ function2_ = |
+ Resolver::ResolveDynamicAnyArgs(zone_, cls_, function_name_); |
+ if (!function2_.IsNull()) { |
+ error_ = CompileFunction(function2_); |
+ if (error_.IsError()) { |
+ return error_.raw(); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ if (!field_.IsNull() && field_.is_const() && field_.is_static()) { |
+ if (field_.StaticValue() == Object::sentinel().raw()) { |
zra
2017/06/05 22:08:57
&& instead of nested if?
rmacnak
2017/06/05 23:14:08
Done.
|
+ // TODO(rmacnak): How to capture an error? |
+ field_.EvaluateInitializer(); |
+ } |
+ } |
+ |
+ if (!function_.IsNull()) { |
+ error_ = CompileFunction(function_); |
+ if (error_.IsError()) { |
+ return error_.raw(); |
+ } |
+ if (add_closure) { |
+ function_ = function_.ImplicitClosureFunction(); |
+ error_ = CompileFunction(function_); |
+ if (error_.IsError()) { |
+ return error_.raw(); |
+ } |
+ } |
+ } |
+ |
+ return Object::null(); |
+ } |
+ |
+ RawObject* CompileFunction(const Function& function) { |
+ if (function.is_abstract()) { |
+ return Object::null(); |
+ } |
+ return Compiler::CompileFunction(thread_, function); |
+ } |
+ |
+ Thread* thread_; |
+ Zone* zone_; |
+ String& uri_; |
+ String& class_name_; |
+ String& function_name_; |
+ String& function_name2_; |
+ Library& lib_; |
+ Class& cls_; |
+ Function& function_; |
+ Function& function2_; |
+ Field& field_; |
+ Object& error_; |
+}; |
+ |
+ |
+DART_EXPORT |
+Dart_Handle Dart_LoadCompilationTrace(uint8_t* buffer, intptr_t buffer_length) { |
+ Thread* thread = Thread::Current(); |
+ API_TIMELINE_DURATION; |
+ DARTSCOPE(thread); |
+ CHECK_NULL(buffer); |
+ CompilationTraceLoader loader(thread); |
+ const Object& error = |
+ Object::Handle(loader.CompileTrace(reinterpret_cast<char*>(buffer))); |
+ if (error.IsError()) { |
+ return Api::NewHandle(T, Error::Cast(error).raw()); |
+ } |
+ return Api::Success(); |
+} |
+ |
+ |
DART_EXPORT |
Dart_Handle Dart_SaveJITFeedback(uint8_t** buffer, intptr_t* buffer_length) { |
#if defined(DART_PRECOMPILED_RUNTIME) |