mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 21:01:50 +00:00
[vm] Load top-level functions and variables lazily
LoadKernel part of startup: 409ms -> 196-210ms. FinishTopLevelClassLoading: 15ms Change-Id: If47f06fe235a70ed08e6a3d75e8f871edae5e45c Reviewed-on: https://dart-review.googlesource.com/c/92155 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Régis Crelier <regis@google.com> Reviewed-by: Zach Anderson <zra@google.com>
This commit is contained in:
parent
20f12ad874
commit
a0516965b4
|
@ -1032,6 +1032,8 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_members, 0, 2) {
|
|||
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
|
||||
const Library& library = Library::Handle(ref.GetLibraryReferent());
|
||||
|
||||
library.EnsureTopLevelClassIsFinalized();
|
||||
|
||||
Instance& member_mirror = Instance::Handle();
|
||||
const GrowableObjectArray& member_mirrors =
|
||||
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
|
|
|
@ -1101,11 +1101,6 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
|
|||
interface_class.DisableCHAImplementorUsers();
|
||||
}
|
||||
}
|
||||
|
||||
// A top level class is loaded eagerly so just finalize it.
|
||||
if (cls.IsTopLevel()) {
|
||||
FinalizeClass(cls);
|
||||
}
|
||||
}
|
||||
|
||||
void ClassFinalizer::FinalizeClass(const Class& cls) {
|
||||
|
@ -1132,8 +1127,8 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
|
|||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// If loading from a kernel, make sure that the class is fully loaded.
|
||||
// Top level classes are always fully loaded.
|
||||
if (!cls.IsTopLevel() && cls.kernel_offset() > 0) {
|
||||
ASSERT(cls.IsTopLevel() || (cls.kernel_offset() > 0));
|
||||
if (!cls.is_loaded()) {
|
||||
kernel::KernelLoader::FinishLoading(cls);
|
||||
if (cls.is_finalized()) {
|
||||
return;
|
||||
|
@ -1181,10 +1176,6 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
|
|||
|
||||
RawError* ClassFinalizer::LoadClassMembers(const Class& cls) {
|
||||
ASSERT(Thread::Current()->IsMutatorThread());
|
||||
// If class is a top level class it is already loaded.
|
||||
if (cls.IsTopLevel()) {
|
||||
return Error::null();
|
||||
}
|
||||
LongJumpScope jump;
|
||||
if (setjmp(*jump.Set()) == 0) {
|
||||
ClassFinalizer::FinalizeClass(cls);
|
||||
|
|
|
@ -298,6 +298,7 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
|
|||
auto& temp_function = Function::Handle(zone);
|
||||
for (intptr_t i = 0; i < libs.Length(); i++) {
|
||||
lib ^= libs.At(i);
|
||||
lib.EnsureTopLevelClassIsFinalized();
|
||||
DictionaryIterator it(lib);
|
||||
while (it.HasNext()) {
|
||||
entry = it.GetNext();
|
||||
|
|
|
@ -900,7 +900,6 @@ RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
|
|||
|
||||
LibraryIndex library_index(library_kernel_data_);
|
||||
intptr_t class_count = library_index.class_count();
|
||||
intptr_t procedure_count = library_index.procedure_count();
|
||||
|
||||
library_helper.ReadUntilIncluding(LibraryHelper::kName);
|
||||
library.SetName(H.DartSymbolObfuscate(library_helper.name_index_));
|
||||
|
@ -969,13 +968,47 @@ RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
|
|||
classes.Add(klass, Heap::kOld);
|
||||
}
|
||||
}
|
||||
helper_.SetOffset(next_class_offset);
|
||||
|
||||
if (loading_native_wrappers_library_ || !register_class) {
|
||||
FinishTopLevelClassLoading(toplevel_class, library, library_index);
|
||||
}
|
||||
|
||||
if (FLAG_enable_mirrors && annotation_count > 0) {
|
||||
ASSERT(annotations_kernel_offset > 0);
|
||||
library.AddLibraryMetadata(toplevel_class, TokenPosition::kNoSource,
|
||||
annotations_kernel_offset);
|
||||
}
|
||||
|
||||
if (register_class) {
|
||||
classes.Add(toplevel_class, Heap::kOld);
|
||||
}
|
||||
if (!library.Loaded()) library.SetLoaded();
|
||||
|
||||
return library.raw();
|
||||
}
|
||||
|
||||
void KernelLoader::FinishTopLevelClassLoading(
|
||||
const Class& toplevel_class,
|
||||
const Library& library,
|
||||
const LibraryIndex& library_index) {
|
||||
if (toplevel_class.is_loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TIMELINE_DURATION(Thread::Current(), Isolate, "FinishTopLevelClassLoading");
|
||||
|
||||
// Offsets within library index are whole program offsets and not
|
||||
// relative to the library.
|
||||
const intptr_t correction = correction_offset_ - library_kernel_offset_;
|
||||
helper_.SetOffset(library_index.ClassOffset(library_index.class_count()) +
|
||||
correction);
|
||||
|
||||
fields_.Clear();
|
||||
functions_.Clear();
|
||||
ActiveClassScope active_class_scope(&active_class_, &toplevel_class);
|
||||
|
||||
// Load toplevel fields.
|
||||
intptr_t field_count = helper_.ReadListLength(); // read list length.
|
||||
const intptr_t field_count = helper_.ReadListLength(); // read list length.
|
||||
for (intptr_t i = 0; i < field_count; ++i) {
|
||||
intptr_t field_offset = helper_.ReaderOffset() - correction_offset_;
|
||||
ActiveMemberScope active_member_scope(&active_class_, NULL);
|
||||
|
@ -1002,7 +1035,7 @@ RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
|
|||
// In the VM all const fields are implicitly final whereas in Kernel they
|
||||
// are not final because they are not explicitly declared that way.
|
||||
const bool is_final = field_helper.IsConst() || field_helper.IsFinal();
|
||||
Field& field = Field::Handle(
|
||||
const Field& field = Field::Handle(
|
||||
Z,
|
||||
Field::NewTopLevel(name, is_final, field_helper.IsConst(), script_class,
|
||||
field_helper.position_, field_helper.end_position_));
|
||||
|
@ -1026,31 +1059,45 @@ RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
|
|||
library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset);
|
||||
}
|
||||
fields_.Add(&field);
|
||||
library.AddObject(field, name);
|
||||
}
|
||||
toplevel_class.AddFields(fields_);
|
||||
|
||||
ASSERT(!toplevel_class.is_loaded());
|
||||
|
||||
// Load toplevel procedures.
|
||||
intptr_t next_procedure_offset = library_index.ProcedureOffset(0);
|
||||
intptr_t next_procedure_offset =
|
||||
library_index.ProcedureOffset(0) + correction;
|
||||
const intptr_t procedure_count = library_index.procedure_count();
|
||||
for (intptr_t i = 0; i < procedure_count; ++i) {
|
||||
helper_.SetOffset(next_procedure_offset);
|
||||
next_procedure_offset = library_index.ProcedureOffset(i + 1);
|
||||
next_procedure_offset = library_index.ProcedureOffset(i + 1) + correction;
|
||||
LoadProcedure(library, toplevel_class, false, next_procedure_offset);
|
||||
// LoadProcedure calls Library::GetMetadata which invokes Dart code
|
||||
// which may recursively trigger class finalization and
|
||||
// FinishTopLevelClassLoading.
|
||||
// In such case, return immediately and avoid overwriting already finalized
|
||||
// functions with freshly loaded and not yet finalized.
|
||||
if (toplevel_class.is_loaded()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_enable_mirrors && annotation_count > 0) {
|
||||
ASSERT(annotations_kernel_offset > 0);
|
||||
library.AddLibraryMetadata(toplevel_class, TokenPosition::kNoSource,
|
||||
annotations_kernel_offset);
|
||||
}
|
||||
|
||||
toplevel_class.SetFields(Array::Handle(MakeFieldsArray()));
|
||||
toplevel_class.SetFunctions(Array::Handle(MakeFunctionsArray()));
|
||||
if (register_class) {
|
||||
classes.Add(toplevel_class, Heap::kOld);
|
||||
}
|
||||
if (!library.Loaded()) library.SetLoaded();
|
||||
|
||||
return library.raw();
|
||||
String& name = String::Handle(Z);
|
||||
for (intptr_t i = 0, n = fields_.length(); i < n; ++i) {
|
||||
const Field* field = fields_.At(i);
|
||||
name = field->name();
|
||||
library.AddObject(*field, name);
|
||||
}
|
||||
for (intptr_t i = 0, n = functions_.length(); i < n; ++i) {
|
||||
const Function* function = functions_.At(i);
|
||||
name = function->name();
|
||||
library.AddObject(*function, name);
|
||||
}
|
||||
|
||||
ASSERT(!toplevel_class.is_loaded());
|
||||
toplevel_class.set_is_loaded(true);
|
||||
}
|
||||
|
||||
void KernelLoader::LoadLibraryImportsAndExports(Library* library,
|
||||
|
@ -1544,7 +1591,7 @@ void KernelLoader::FinishClassLoading(const Class& klass,
|
|||
}
|
||||
|
||||
void KernelLoader::FinishLoading(const Class& klass) {
|
||||
ASSERT(klass.kernel_offset() > 0);
|
||||
ASSERT(klass.IsTopLevel() || (klass.kernel_offset() > 0));
|
||||
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
const Script& script = Script::Handle(zone, klass.script());
|
||||
|
@ -1556,10 +1603,17 @@ void KernelLoader::FinishLoading(const Class& klass) {
|
|||
const intptr_t library_kernel_offset = library.kernel_offset();
|
||||
ASSERT(library_kernel_offset > 0);
|
||||
|
||||
const intptr_t class_offset = klass.kernel_offset();
|
||||
KernelLoader kernel_loader(script, library_kernel_data,
|
||||
library_kernel_offset);
|
||||
LibraryIndex library_index(library_kernel_data);
|
||||
|
||||
if (klass.IsTopLevel()) {
|
||||
ASSERT(klass.raw() == toplevel_class.raw());
|
||||
kernel_loader.FinishTopLevelClassLoading(klass, library, library_index);
|
||||
return;
|
||||
}
|
||||
|
||||
const intptr_t class_offset = klass.kernel_offset();
|
||||
ClassIndex class_index(
|
||||
library_kernel_data, class_offset,
|
||||
// Class offsets in library index are whole program offsets.
|
||||
|
@ -1790,14 +1844,6 @@ void KernelLoader::LoadProcedure(const Library& library,
|
|||
// function_node_helper are no longer used.
|
||||
helper_.SetOffset(procedure_end);
|
||||
|
||||
if (!in_class) {
|
||||
library.AddObject(function, name);
|
||||
ASSERT(!Object::Handle(
|
||||
Z, library.LookupObjectAllowPrivate(
|
||||
H.DartProcedureName(procedure_helper.canonical_name_)))
|
||||
.IsNull());
|
||||
}
|
||||
|
||||
if (annotation_count > 0) {
|
||||
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
|
||||
procedure_offset);
|
||||
|
|
|
@ -178,6 +178,10 @@ class KernelLoader : public ValueObject {
|
|||
|
||||
RawLibrary* LoadLibrary(intptr_t index);
|
||||
|
||||
void FinishTopLevelClassLoading(const Class& toplevel_class,
|
||||
const Library& library,
|
||||
const LibraryIndex& library_index);
|
||||
|
||||
static void FinishLoading(const Class& klass);
|
||||
|
||||
void ReadObfuscationProhibitions();
|
||||
|
@ -321,9 +325,9 @@ class KernelLoader : public ValueObject {
|
|||
|
||||
void EnsurePragmaClassIsLookedUp() {
|
||||
if (pragma_class_.IsNull()) {
|
||||
const Library& internal_lib =
|
||||
Library::Handle(zone_, dart::Library::InternalLibrary());
|
||||
pragma_class_ = internal_lib.LookupClass(Symbols::Pragma());
|
||||
const Library& core_lib =
|
||||
Library::Handle(zone_, dart::Library::CoreLibrary());
|
||||
pragma_class_ = core_lib.LookupLocalClass(Symbols::Pragma());
|
||||
ASSERT(!pragma_class_.IsNull());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9882,6 +9882,7 @@ RawObject* Library::ResolveName(const String& name) const {
|
|||
if (FLAG_use_lib_cache && LookupResolvedNamesCache(name, &obj)) {
|
||||
return obj.raw();
|
||||
}
|
||||
EnsureTopLevelClassIsFinalized();
|
||||
obj = LookupLocalObject(name);
|
||||
if (!obj.IsNull()) {
|
||||
// Names that are in this library's dictionary and are unmangled
|
||||
|
@ -10169,18 +10170,6 @@ RawObject* Library::LookupEntry(const String& name, intptr_t* index) const {
|
|||
return Object::null();
|
||||
}
|
||||
|
||||
void Library::ReplaceObject(const Object& obj, const String& name) const {
|
||||
ASSERT(!Compiler::IsBackgroundCompilation());
|
||||
ASSERT(obj.IsClass() || obj.IsFunction() || obj.IsField());
|
||||
ASSERT(LookupLocalObject(name) != Object::null());
|
||||
|
||||
intptr_t index;
|
||||
LookupEntry(name, &index);
|
||||
// The value is guaranteed to be found.
|
||||
const Array& dict = Array::Handle(dictionary());
|
||||
dict.SetAt(index, obj);
|
||||
}
|
||||
|
||||
void Library::AddClass(const Class& cls) const {
|
||||
ASSERT(!Compiler::IsBackgroundCompilation());
|
||||
const String& class_name = String::Handle(cls.Name());
|
||||
|
@ -10307,6 +10296,22 @@ RawScript* Library::LookupScript(const String& url,
|
|||
return Script::null();
|
||||
}
|
||||
|
||||
void Library::EnsureTopLevelClassIsFinalized() const {
|
||||
if (toplevel_class() == Object::null()) {
|
||||
return;
|
||||
}
|
||||
Thread* thread = Thread::Current();
|
||||
const Class& cls = Class::Handle(thread->zone(), toplevel_class());
|
||||
if (cls.is_finalized()) {
|
||||
return;
|
||||
}
|
||||
const Error& error =
|
||||
Error::Handle(thread->zone(), cls.EnsureIsFinalized(thread));
|
||||
if (!error.IsNull()) {
|
||||
Exceptions::PropagateError(error);
|
||||
}
|
||||
}
|
||||
|
||||
RawObject* Library::LookupLocalObject(const String& name) const {
|
||||
intptr_t index;
|
||||
return LookupEntry(name, &index);
|
||||
|
@ -10314,6 +10319,7 @@ RawObject* Library::LookupLocalObject(const String& name) const {
|
|||
|
||||
RawObject* Library::LookupLocalOrReExportObject(const String& name) const {
|
||||
intptr_t index;
|
||||
EnsureTopLevelClassIsFinalized();
|
||||
const Object& result = Object::Handle(LookupEntry(name, &index));
|
||||
if (!result.IsNull() && !result.IsLibraryPrefix()) {
|
||||
return result.raw();
|
||||
|
@ -10322,6 +10328,7 @@ RawObject* Library::LookupLocalOrReExportObject(const String& name) const {
|
|||
}
|
||||
|
||||
RawField* Library::LookupFieldAllowPrivate(const String& name) const {
|
||||
EnsureTopLevelClassIsFinalized();
|
||||
Object& obj = Object::Handle(LookupObjectAllowPrivate(name));
|
||||
if (obj.IsField()) {
|
||||
return Field::Cast(obj).raw();
|
||||
|
@ -10330,6 +10337,7 @@ RawField* Library::LookupFieldAllowPrivate(const String& name) const {
|
|||
}
|
||||
|
||||
RawField* Library::LookupLocalField(const String& name) const {
|
||||
EnsureTopLevelClassIsFinalized();
|
||||
Object& obj = Object::Handle(LookupLocalObjectAllowPrivate(name));
|
||||
if (obj.IsField()) {
|
||||
return Field::Cast(obj).raw();
|
||||
|
@ -10338,6 +10346,7 @@ RawField* Library::LookupLocalField(const String& name) const {
|
|||
}
|
||||
|
||||
RawFunction* Library::LookupFunctionAllowPrivate(const String& name) const {
|
||||
EnsureTopLevelClassIsFinalized();
|
||||
Object& obj = Object::Handle(LookupObjectAllowPrivate(name));
|
||||
if (obj.IsFunction()) {
|
||||
return Function::Cast(obj).raw();
|
||||
|
@ -10346,6 +10355,7 @@ RawFunction* Library::LookupFunctionAllowPrivate(const String& name) const {
|
|||
}
|
||||
|
||||
RawFunction* Library::LookupLocalFunction(const String& name) const {
|
||||
EnsureTopLevelClassIsFinalized();
|
||||
Object& obj = Object::Handle(LookupLocalObjectAllowPrivate(name));
|
||||
if (obj.IsFunction()) {
|
||||
return Function::Cast(obj).raw();
|
||||
|
@ -10443,7 +10453,10 @@ RawObject* Library::LookupImportedObject(const String& name) const {
|
|||
}
|
||||
|
||||
RawClass* Library::LookupClass(const String& name) const {
|
||||
Object& obj = Object::Handle(ResolveName(name));
|
||||
Object& obj = Object::Handle(LookupLocalObject(name));
|
||||
if (obj.IsNull() && !ShouldBePrivate(name)) {
|
||||
obj = LookupImportedObject(name);
|
||||
}
|
||||
if (obj.IsClass()) {
|
||||
return Class::Cast(obj).raw();
|
||||
}
|
||||
|
@ -11708,6 +11721,8 @@ RawObject* Namespace::Lookup(const String& name,
|
|||
}
|
||||
}
|
||||
|
||||
lib.EnsureTopLevelClassIsFinalized();
|
||||
|
||||
intptr_t ignore = 0;
|
||||
// Lookup the name in the library's symbols.
|
||||
Object& obj = Object::Handle(zone, lib.LookupEntry(name, &ignore));
|
||||
|
|
|
@ -3689,12 +3689,9 @@ class Library : public Object {
|
|||
// more regular.
|
||||
void AddClass(const Class& cls) const;
|
||||
void AddObject(const Object& obj, const String& name) const;
|
||||
void ReplaceObject(const Object& obj, const String& name) const;
|
||||
RawObject* LookupReExport(const String& name,
|
||||
ZoneGrowableArray<intptr_t>* visited = NULL) const;
|
||||
RawObject* LookupObjectAllowPrivate(const String& name) const;
|
||||
RawObject* LookupLocalObjectAllowPrivate(const String& name) const;
|
||||
RawObject* LookupLocalObject(const String& name) const;
|
||||
RawObject* LookupLocalOrReExportObject(const String& name) const;
|
||||
RawObject* LookupImportedObject(const String& name) const;
|
||||
RawClass* LookupClass(const String& name) const;
|
||||
|
@ -3897,6 +3894,9 @@ class Library : public Object {
|
|||
// for a top level getter 'name' that returns a closure.
|
||||
RawObject* GetFunctionClosure(const String& name) const;
|
||||
|
||||
// Ensures that all top-level functions and variables (fields) are loaded.
|
||||
void EnsureTopLevelClassIsFinalized() const;
|
||||
|
||||
private:
|
||||
static const int kInitialImportsCapacity = 4;
|
||||
static const int kImportsCapacityIncrement = 8;
|
||||
|
@ -3935,6 +3935,8 @@ class Library : public Object {
|
|||
void RehashDictionary(const Array& old_dict, intptr_t new_dict_size) const;
|
||||
static RawLibrary* NewLibraryHelper(const String& url, bool import_core_lib);
|
||||
RawObject* LookupEntry(const String& name, intptr_t* index) const;
|
||||
RawObject* LookupLocalObjectAllowPrivate(const String& name) const;
|
||||
RawObject* LookupLocalObject(const String& name) const;
|
||||
|
||||
void AllocatePrivateKey() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue