Skip to content

Commit a051696

Browse files
alexmarkovcommit-bot@chromium.org
authored and
commit-bot@chromium.org
committed
[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>
1 parent 20f12ad commit a051696

File tree

7 files changed

+119
-58
lines changed

7 files changed

+119
-58
lines changed

runtime/lib/mirrors.cc

+2
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,8 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_members, 0, 2) {
10321032
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
10331033
const Library& library = Library::Handle(ref.GetLibraryReferent());
10341034

1035+
library.EnsureTopLevelClassIsFinalized();
1036+
10351037
Instance& member_mirror = Instance::Handle();
10361038
const GrowableObjectArray& member_mirrors =
10371039
GrowableObjectArray::Handle(GrowableObjectArray::New());

runtime/vm/class_finalizer.cc

+2-11
Original file line numberDiff line numberDiff line change
@@ -1101,11 +1101,6 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
11011101
interface_class.DisableCHAImplementorUsers();
11021102
}
11031103
}
1104-
1105-
// A top level class is loaded eagerly so just finalize it.
1106-
if (cls.IsTopLevel()) {
1107-
FinalizeClass(cls);
1108-
}
11091104
}
11101105

11111106
void ClassFinalizer::FinalizeClass(const Class& cls) {
@@ -1132,8 +1127,8 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
11321127

11331128
#if !defined(DART_PRECOMPILED_RUNTIME)
11341129
// If loading from a kernel, make sure that the class is fully loaded.
1135-
// Top level classes are always fully loaded.
1136-
if (!cls.IsTopLevel() && cls.kernel_offset() > 0) {
1130+
ASSERT(cls.IsTopLevel() || (cls.kernel_offset() > 0));
1131+
if (!cls.is_loaded()) {
11371132
kernel::KernelLoader::FinishLoading(cls);
11381133
if (cls.is_finalized()) {
11391134
return;
@@ -1181,10 +1176,6 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
11811176

11821177
RawError* ClassFinalizer::LoadClassMembers(const Class& cls) {
11831178
ASSERT(Thread::Current()->IsMutatorThread());
1184-
// If class is a top level class it is already loaded.
1185-
if (cls.IsTopLevel()) {
1186-
return Error::null();
1187-
}
11881179
LongJumpScope jump;
11891180
if (setjmp(*jump.Set()) == 0) {
11901181
ClassFinalizer::FinalizeClass(cls);

runtime/vm/kernel.cc

+1
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
298298
auto& temp_function = Function::Handle(zone);
299299
for (intptr_t i = 0; i < libs.Length(); i++) {
300300
lib ^= libs.At(i);
301+
lib.EnsureTopLevelClassIsFinalized();
301302
DictionaryIterator it(lib);
302303
while (it.HasNext()) {
303304
entry = it.GetNext();

runtime/vm/kernel_loader.cc

+74-28
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,6 @@ RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
900900

901901
LibraryIndex library_index(library_kernel_data_);
902902
intptr_t class_count = library_index.class_count();
903-
intptr_t procedure_count = library_index.procedure_count();
904903

905904
library_helper.ReadUntilIncluding(LibraryHelper::kName);
906905
library.SetName(H.DartSymbolObfuscate(library_helper.name_index_));
@@ -969,13 +968,47 @@ RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
969968
classes.Add(klass, Heap::kOld);
970969
}
971970
}
972-
helper_.SetOffset(next_class_offset);
971+
972+
if (loading_native_wrappers_library_ || !register_class) {
973+
FinishTopLevelClassLoading(toplevel_class, library, library_index);
974+
}
975+
976+
if (FLAG_enable_mirrors && annotation_count > 0) {
977+
ASSERT(annotations_kernel_offset > 0);
978+
library.AddLibraryMetadata(toplevel_class, TokenPosition::kNoSource,
979+
annotations_kernel_offset);
980+
}
981+
982+
if (register_class) {
983+
classes.Add(toplevel_class, Heap::kOld);
984+
}
985+
if (!library.Loaded()) library.SetLoaded();
986+
987+
return library.raw();
988+
}
989+
990+
void KernelLoader::FinishTopLevelClassLoading(
991+
const Class& toplevel_class,
992+
const Library& library,
993+
const LibraryIndex& library_index) {
994+
if (toplevel_class.is_loaded()) {
995+
return;
996+
}
997+
998+
TIMELINE_DURATION(Thread::Current(), Isolate, "FinishTopLevelClassLoading");
999+
1000+
// Offsets within library index are whole program offsets and not
1001+
// relative to the library.
1002+
const intptr_t correction = correction_offset_ - library_kernel_offset_;
1003+
helper_.SetOffset(library_index.ClassOffset(library_index.class_count()) +
1004+
correction);
9731005

9741006
fields_.Clear();
9751007
functions_.Clear();
9761008
ActiveClassScope active_class_scope(&active_class_, &toplevel_class);
1009+
9771010
// Load toplevel fields.
978-
intptr_t field_count = helper_.ReadListLength(); // read list length.
1011+
const intptr_t field_count = helper_.ReadListLength(); // read list length.
9791012
for (intptr_t i = 0; i < field_count; ++i) {
9801013
intptr_t field_offset = helper_.ReaderOffset() - correction_offset_;
9811014
ActiveMemberScope active_member_scope(&active_class_, NULL);
@@ -1002,7 +1035,7 @@ RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
10021035
// In the VM all const fields are implicitly final whereas in Kernel they
10031036
// are not final because they are not explicitly declared that way.
10041037
const bool is_final = field_helper.IsConst() || field_helper.IsFinal();
1005-
Field& field = Field::Handle(
1038+
const Field& field = Field::Handle(
10061039
Z,
10071040
Field::NewTopLevel(name, is_final, field_helper.IsConst(), script_class,
10081041
field_helper.position_, field_helper.end_position_));
@@ -1026,31 +1059,45 @@ RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
10261059
library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset);
10271060
}
10281061
fields_.Add(&field);
1029-
library.AddObject(field, name);
10301062
}
1031-
toplevel_class.AddFields(fields_);
1063+
1064+
ASSERT(!toplevel_class.is_loaded());
10321065

10331066
// Load toplevel procedures.
1034-
intptr_t next_procedure_offset = library_index.ProcedureOffset(0);
1067+
intptr_t next_procedure_offset =
1068+
library_index.ProcedureOffset(0) + correction;
1069+
const intptr_t procedure_count = library_index.procedure_count();
10351070
for (intptr_t i = 0; i < procedure_count; ++i) {
10361071
helper_.SetOffset(next_procedure_offset);
1037-
next_procedure_offset = library_index.ProcedureOffset(i + 1);
1072+
next_procedure_offset = library_index.ProcedureOffset(i + 1) + correction;
10381073
LoadProcedure(library, toplevel_class, false, next_procedure_offset);
1074+
// LoadProcedure calls Library::GetMetadata which invokes Dart code
1075+
// which may recursively trigger class finalization and
1076+
// FinishTopLevelClassLoading.
1077+
// In such case, return immediately and avoid overwriting already finalized
1078+
// functions with freshly loaded and not yet finalized.
1079+
if (toplevel_class.is_loaded()) {
1080+
return;
1081+
}
10391082
}
10401083

1041-
if (FLAG_enable_mirrors && annotation_count > 0) {
1042-
ASSERT(annotations_kernel_offset > 0);
1043-
library.AddLibraryMetadata(toplevel_class, TokenPosition::kNoSource,
1044-
annotations_kernel_offset);
1045-
}
1046-
1084+
toplevel_class.SetFields(Array::Handle(MakeFieldsArray()));
10471085
toplevel_class.SetFunctions(Array::Handle(MakeFunctionsArray()));
1048-
if (register_class) {
1049-
classes.Add(toplevel_class, Heap::kOld);
1086+
1087+
String& name = String::Handle(Z);
1088+
for (intptr_t i = 0, n = fields_.length(); i < n; ++i) {
1089+
const Field* field = fields_.At(i);
1090+
name = field->name();
1091+
library.AddObject(*field, name);
1092+
}
1093+
for (intptr_t i = 0, n = functions_.length(); i < n; ++i) {
1094+
const Function* function = functions_.At(i);
1095+
name = function->name();
1096+
library.AddObject(*function, name);
10501097
}
1051-
if (!library.Loaded()) library.SetLoaded();
10521098

1053-
return library.raw();
1099+
ASSERT(!toplevel_class.is_loaded());
1100+
toplevel_class.set_is_loaded(true);
10541101
}
10551102

10561103
void KernelLoader::LoadLibraryImportsAndExports(Library* library,
@@ -1544,7 +1591,7 @@ void KernelLoader::FinishClassLoading(const Class& klass,
15441591
}
15451592

15461593
void KernelLoader::FinishLoading(const Class& klass) {
1547-
ASSERT(klass.kernel_offset() > 0);
1594+
ASSERT(klass.IsTopLevel() || (klass.kernel_offset() > 0));
15481595

15491596
Zone* zone = Thread::Current()->zone();
15501597
const Script& script = Script::Handle(zone, klass.script());
@@ -1556,10 +1603,17 @@ void KernelLoader::FinishLoading(const Class& klass) {
15561603
const intptr_t library_kernel_offset = library.kernel_offset();
15571604
ASSERT(library_kernel_offset > 0);
15581605

1559-
const intptr_t class_offset = klass.kernel_offset();
15601606
KernelLoader kernel_loader(script, library_kernel_data,
15611607
library_kernel_offset);
15621608
LibraryIndex library_index(library_kernel_data);
1609+
1610+
if (klass.IsTopLevel()) {
1611+
ASSERT(klass.raw() == toplevel_class.raw());
1612+
kernel_loader.FinishTopLevelClassLoading(klass, library, library_index);
1613+
return;
1614+
}
1615+
1616+
const intptr_t class_offset = klass.kernel_offset();
15631617
ClassIndex class_index(
15641618
library_kernel_data, class_offset,
15651619
// Class offsets in library index are whole program offsets.
@@ -1790,14 +1844,6 @@ void KernelLoader::LoadProcedure(const Library& library,
17901844
// function_node_helper are no longer used.
17911845
helper_.SetOffset(procedure_end);
17921846

1793-
if (!in_class) {
1794-
library.AddObject(function, name);
1795-
ASSERT(!Object::Handle(
1796-
Z, library.LookupObjectAllowPrivate(
1797-
H.DartProcedureName(procedure_helper.canonical_name_)))
1798-
.IsNull());
1799-
}
1800-
18011847
if (annotation_count > 0) {
18021848
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
18031849
procedure_offset);

runtime/vm/kernel_loader.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ class KernelLoader : public ValueObject {
178178

179179
RawLibrary* LoadLibrary(intptr_t index);
180180

181+
void FinishTopLevelClassLoading(const Class& toplevel_class,
182+
const Library& library,
183+
const LibraryIndex& library_index);
184+
181185
static void FinishLoading(const Class& klass);
182186

183187
void ReadObfuscationProhibitions();
@@ -321,9 +325,9 @@ class KernelLoader : public ValueObject {
321325

322326
void EnsurePragmaClassIsLookedUp() {
323327
if (pragma_class_.IsNull()) {
324-
const Library& internal_lib =
325-
Library::Handle(zone_, dart::Library::InternalLibrary());
326-
pragma_class_ = internal_lib.LookupClass(Symbols::Pragma());
328+
const Library& core_lib =
329+
Library::Handle(zone_, dart::Library::CoreLibrary());
330+
pragma_class_ = core_lib.LookupLocalClass(Symbols::Pragma());
327331
ASSERT(!pragma_class_.IsNull());
328332
}
329333
}

runtime/vm/object.cc

+28-13
Original file line numberDiff line numberDiff line change
@@ -9882,6 +9882,7 @@ RawObject* Library::ResolveName(const String& name) const {
98829882
if (FLAG_use_lib_cache && LookupResolvedNamesCache(name, &obj)) {
98839883
return obj.raw();
98849884
}
9885+
EnsureTopLevelClassIsFinalized();
98859886
obj = LookupLocalObject(name);
98869887
if (!obj.IsNull()) {
98879888
// 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 {
1016910170
return Object::null();
1017010171
}
1017110172

10172-
void Library::ReplaceObject(const Object& obj, const String& name) const {
10173-
ASSERT(!Compiler::IsBackgroundCompilation());
10174-
ASSERT(obj.IsClass() || obj.IsFunction() || obj.IsField());
10175-
ASSERT(LookupLocalObject(name) != Object::null());
10176-
10177-
intptr_t index;
10178-
LookupEntry(name, &index);
10179-
// The value is guaranteed to be found.
10180-
const Array& dict = Array::Handle(dictionary());
10181-
dict.SetAt(index, obj);
10182-
}
10183-
1018410173
void Library::AddClass(const Class& cls) const {
1018510174
ASSERT(!Compiler::IsBackgroundCompilation());
1018610175
const String& class_name = String::Handle(cls.Name());
@@ -10307,13 +10296,30 @@ RawScript* Library::LookupScript(const String& url,
1030710296
return Script::null();
1030810297
}
1030910298

10299+
void Library::EnsureTopLevelClassIsFinalized() const {
10300+
if (toplevel_class() == Object::null()) {
10301+
return;
10302+
}
10303+
Thread* thread = Thread::Current();
10304+
const Class& cls = Class::Handle(thread->zone(), toplevel_class());
10305+
if (cls.is_finalized()) {
10306+
return;
10307+
}
10308+
const Error& error =
10309+
Error::Handle(thread->zone(), cls.EnsureIsFinalized(thread));
10310+
if (!error.IsNull()) {
10311+
Exceptions::PropagateError(error);
10312+
}
10313+
}
10314+
1031010315
RawObject* Library::LookupLocalObject(const String& name) const {
1031110316
intptr_t index;
1031210317
return LookupEntry(name, &index);
1031310318
}
1031410319

1031510320
RawObject* Library::LookupLocalOrReExportObject(const String& name) const {
1031610321
intptr_t index;
10322+
EnsureTopLevelClassIsFinalized();
1031710323
const Object& result = Object::Handle(LookupEntry(name, &index));
1031810324
if (!result.IsNull() && !result.IsLibraryPrefix()) {
1031910325
return result.raw();
@@ -10322,6 +10328,7 @@ RawObject* Library::LookupLocalOrReExportObject(const String& name) const {
1032210328
}
1032310329

1032410330
RawField* Library::LookupFieldAllowPrivate(const String& name) const {
10331+
EnsureTopLevelClassIsFinalized();
1032510332
Object& obj = Object::Handle(LookupObjectAllowPrivate(name));
1032610333
if (obj.IsField()) {
1032710334
return Field::Cast(obj).raw();
@@ -10330,6 +10337,7 @@ RawField* Library::LookupFieldAllowPrivate(const String& name) const {
1033010337
}
1033110338

1033210339
RawField* Library::LookupLocalField(const String& name) const {
10340+
EnsureTopLevelClassIsFinalized();
1033310341
Object& obj = Object::Handle(LookupLocalObjectAllowPrivate(name));
1033410342
if (obj.IsField()) {
1033510343
return Field::Cast(obj).raw();
@@ -10338,6 +10346,7 @@ RawField* Library::LookupLocalField(const String& name) const {
1033810346
}
1033910347

1034010348
RawFunction* Library::LookupFunctionAllowPrivate(const String& name) const {
10349+
EnsureTopLevelClassIsFinalized();
1034110350
Object& obj = Object::Handle(LookupObjectAllowPrivate(name));
1034210351
if (obj.IsFunction()) {
1034310352
return Function::Cast(obj).raw();
@@ -10346,6 +10355,7 @@ RawFunction* Library::LookupFunctionAllowPrivate(const String& name) const {
1034610355
}
1034710356

1034810357
RawFunction* Library::LookupLocalFunction(const String& name) const {
10358+
EnsureTopLevelClassIsFinalized();
1034910359
Object& obj = Object::Handle(LookupLocalObjectAllowPrivate(name));
1035010360
if (obj.IsFunction()) {
1035110361
return Function::Cast(obj).raw();
@@ -10443,7 +10453,10 @@ RawObject* Library::LookupImportedObject(const String& name) const {
1044310453
}
1044410454

1044510455
RawClass* Library::LookupClass(const String& name) const {
10446-
Object& obj = Object::Handle(ResolveName(name));
10456+
Object& obj = Object::Handle(LookupLocalObject(name));
10457+
if (obj.IsNull() && !ShouldBePrivate(name)) {
10458+
obj = LookupImportedObject(name);
10459+
}
1044710460
if (obj.IsClass()) {
1044810461
return Class::Cast(obj).raw();
1044910462
}
@@ -11708,6 +11721,8 @@ RawObject* Namespace::Lookup(const String& name,
1170811721
}
1170911722
}
1171011723

11724+
lib.EnsureTopLevelClassIsFinalized();
11725+
1171111726
intptr_t ignore = 0;
1171211727
// Lookup the name in the library's symbols.
1171311728
Object& obj = Object::Handle(zone, lib.LookupEntry(name, &ignore));

runtime/vm/object.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -3689,12 +3689,9 @@ class Library : public Object {
36893689
// more regular.
36903690
void AddClass(const Class& cls) const;
36913691
void AddObject(const Object& obj, const String& name) const;
3692-
void ReplaceObject(const Object& obj, const String& name) const;
36933692
RawObject* LookupReExport(const String& name,
36943693
ZoneGrowableArray<intptr_t>* visited = NULL) const;
36953694
RawObject* LookupObjectAllowPrivate(const String& name) const;
3696-
RawObject* LookupLocalObjectAllowPrivate(const String& name) const;
3697-
RawObject* LookupLocalObject(const String& name) const;
36983695
RawObject* LookupLocalOrReExportObject(const String& name) const;
36993696
RawObject* LookupImportedObject(const String& name) const;
37003697
RawClass* LookupClass(const String& name) const;
@@ -3897,6 +3894,9 @@ class Library : public Object {
38973894
// for a top level getter 'name' that returns a closure.
38983895
RawObject* GetFunctionClosure(const String& name) const;
38993896

3897+
// Ensures that all top-level functions and variables (fields) are loaded.
3898+
void EnsureTopLevelClassIsFinalized() const;
3899+
39003900
private:
39013901
static const int kInitialImportsCapacity = 4;
39023902
static const int kImportsCapacityIncrement = 8;
@@ -3935,6 +3935,8 @@ class Library : public Object {
39353935
void RehashDictionary(const Array& old_dict, intptr_t new_dict_size) const;
39363936
static RawLibrary* NewLibraryHelper(const String& url, bool import_core_lib);
39373937
RawObject* LookupEntry(const String& name, intptr_t* index) const;
3938+
RawObject* LookupLocalObjectAllowPrivate(const String& name) const;
3939+
RawObject* LookupLocalObject(const String& name) const;
39383940

39393941
void AllocatePrivateKey() const;
39403942

0 commit comments

Comments
 (0)