Index: runtime/vm/compilation_trace.cc |
diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f972dfa1f9d86aadd048a4543f7b1a5ac302014c |
--- /dev/null |
+++ b/runtime/vm/compilation_trace.cc |
@@ -0,0 +1,228 @@ |
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+#include "vm/compilation_trace.h" |
+ |
+#include "vm/longjump.h" |
+#include "vm/object_store.h" |
+#include "vm/resolver.h" |
+#include "vm/symbols.h" |
+ |
+namespace dart { |
+ |
+CompilationTraceSaver::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 CompilationTraceSaver::Visit(const Function& function) { |
+ if (!function.HasCode()) { |
+ return; |
+ } |
+ |
+ 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()); |
+} |
+ |
+ |
+CompilationTraceLoader::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* CompilationTraceLoader::CompileTrace(char* buffer) { |
+ // First compile functions named in the trace. |
+ 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. These aren't found with the normal |
+ // 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(); |
+} |
+ |
+ |
+RawObject* CompilationTraceLoader::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() && |
+ (field_.StaticValue() == Object::sentinel().raw())) { |
+ error_ = EvaluateInitializer(field_); |
+ if (error_.IsError()) { |
+ return error_.raw(); |
+ } |
+ } |
+ |
+ 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* CompilationTraceLoader::CompileFunction(const Function& function) { |
+ if (function.is_abstract()) { |
+ return Object::null(); |
+ } |
+ return Compiler::CompileFunction(thread_, function); |
+} |
+ |
+ |
+RawObject* CompilationTraceLoader::EvaluateInitializer(const Field& field) { |
+ LongJumpScope jump; |
+ if (setjmp(*jump.Set()) == 0) { |
+ field_.EvaluateInitializer(); |
+ } else { |
+ Thread* thread = Thread::Current(); |
+ const Error& error = Error::Handle(thread->sticky_error()); |
+ thread->clear_sticky_error(); |
+ return error.raw(); |
+ } |
+ return Object::null(); |
+} |
+ |
+} // namespace dart |