Chromium Code Reviews| 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) |