mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:59:38 +00:00
257 lines
8.3 KiB
C++
257 lines
8.3 KiB
C++
// 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; // 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;
|
|
}
|
|
|
|
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_)) {}
|
|
|
|
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 = reinterpret_cast<char*>(buffer);
|
|
char* limit = cursor + size;
|
|
while (cursor < limit) {
|
|
char* uri = cursor;
|
|
char* comma1 = FindCharacter(uri, ',', limit);
|
|
if (comma1 == NULL) {
|
|
break;
|
|
}
|
|
*comma1 = 0;
|
|
char* cls_name = comma1 + 1;
|
|
char* comma2 = FindCharacter(cls_name, ',', limit);
|
|
if (comma2 == NULL) {
|
|
break;
|
|
}
|
|
*comma2 = 0;
|
|
char* func_name = comma2 + 1;
|
|
char* newline = FindCharacter(func_name, '\n', limit);
|
|
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. 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++) {
|
|
function_ ^= closure_functions.At(i);
|
|
function2_ = function_.parent_function();
|
|
if (function2_.HasCode()) {
|
|
error_ = CompileFunction(function_);
|
|
if (error_.IsError()) {
|
|
return error_.raw();
|
|
}
|
|
}
|
|
}
|
|
|
|
return Object::null();
|
|
}
|
|
|
|
// 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) {
|
|
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 (function_.IsNull() && is_getter) {
|
|
// Maybe this was 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
|