Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(852)

Unified Diff: runtime/vm/precompiler.cc

Issue 1686773002: Precompilation: drop unused types and type arguments and empty classes and libraries. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/precompiler.cc
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 65b6166499409ef1490454add290f36d4f301c79..852eaa3dde8c71dae7620128697009093a4681b5 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -140,12 +140,19 @@ Precompiler::Precompiler(Thread* thread, bool reset_fields) :
selector_count_(0),
dropped_function_count_(0),
dropped_field_count_(0),
+ dropped_class_count_(0),
+ dropped_typearg_count_(0),
+ dropped_type_count_(0),
+ dropped_library_count_(0),
libraries_(GrowableObjectArray::Handle(I->object_store()->libraries())),
pending_functions_(
GrowableObjectArray::Handle(GrowableObjectArray::New())),
sent_selectors_(),
enqueued_functions_(),
fields_to_retain_(),
+ classes_to_retain_(),
+ typeargs_to_retain_(),
+ types_to_retain_(),
error_(Error::Handle()) {
}
@@ -166,7 +173,7 @@ void Precompiler::DoCompileAll(
const intptr_t kPrecompilerRounds = 1;
for (intptr_t round = 0; round < kPrecompilerRounds; round++) {
if (FLAG_trace_precompiler) {
- OS::Print("Precompiler round %" Pd "\n", round);
+ THR_Print("Precompiler round %" Pd "\n", round);
}
if (round > 0) {
@@ -197,8 +204,11 @@ void Precompiler::DoCompileAll(
DropFunctions();
DropFields();
-
- // TODO(rmacnak): DropEmptyClasses();
+ TraceTypesFromRetainedClasses();
+ DropTypes();
+ DropTypeArguments();
+ DropClasses();
+ DropLibraries();
BindStaticCalls();
@@ -219,15 +229,17 @@ void Precompiler::DoCompileAll(
intptr_t dropped_symbols_count = Symbols::Compact(I);
if (FLAG_trace_precompiler) {
- THR_Print("Precompiled %" Pd " functions, %" Pd " dynamic types,"
- " %" Pd " dynamic selectors.\n Dropped %" Pd " functions, %" Pd
- " fields, %" Pd " symbols.\n",
- function_count_,
- class_count_,
- selector_count_,
- dropped_function_count_,
- dropped_field_count_,
- dropped_symbols_count);
+ THR_Print("Precompiled %" Pd " functions,", function_count_);
+ THR_Print(" %" Pd " dynamic types,", class_count_);
+ THR_Print(" %" Pd " dynamic selectors.\n", selector_count_);
+
+ THR_Print("Dropped %" Pd " functions,", dropped_function_count_);
+ THR_Print(" %" Pd " fields,", dropped_field_count_);
+ THR_Print(" %" Pd " symbols,", dropped_symbols_count);
+ THR_Print(" %" Pd " types,", dropped_type_count_);
+ THR_Print(" %" Pd " type arguments,", dropped_typearg_count_);
+ THR_Print(" %" Pd " classes,", dropped_class_count_);
+ THR_Print(" %" Pd " libraries.\n", dropped_library_count_);
}
}
@@ -236,6 +248,7 @@ void Precompiler::ClearAllCode() {
class ClearCodeFunctionVisitor : public FunctionVisitor {
void VisitFunction(const Function& function) {
function.ClearCode();
+ function.ClearICDataArray();
}
};
ClearCodeFunctionVisitor visitor;
@@ -252,84 +265,25 @@ void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) {
AddSelector(Symbols::Call()); // For speed, not correctness.
// Allocated from C++.
- static const intptr_t kExternallyAllocatedCids[] = {
- kBoolCid,
- kNullCid,
- kClosureCid,
-
- kSmiCid,
- kMintCid,
- kBigintCid,
- kDoubleCid,
-
- kOneByteStringCid,
- kTwoByteStringCid,
- kExternalOneByteStringCid,
- kExternalTwoByteStringCid,
-
- kArrayCid,
- kImmutableArrayCid,
- kGrowableObjectArrayCid,
- kLinkedHashMapCid,
-
- kTypedDataUint8ClampedArrayCid,
- kTypedDataUint8ArrayCid,
- kTypedDataUint16ArrayCid,
- kTypedDataUint32ArrayCid,
- kTypedDataUint64ArrayCid,
- kTypedDataInt8ArrayCid,
- kTypedDataInt16ArrayCid,
- kTypedDataInt32ArrayCid,
- kTypedDataInt64ArrayCid,
-
- kExternalTypedDataUint8ArrayCid,
- kExternalTypedDataUint16ArrayCid,
- kExternalTypedDataUint32ArrayCid,
- kExternalTypedDataUint64ArrayCid,
- kExternalTypedDataInt8ArrayCid,
- kExternalTypedDataInt16ArrayCid,
- kExternalTypedDataInt32ArrayCid,
- kExternalTypedDataInt64ArrayCid,
-
- kTypedDataFloat32ArrayCid,
- kTypedDataFloat64ArrayCid,
-
- kTypedDataFloat32x4ArrayCid,
- kTypedDataInt32x4ArrayCid,
- kTypedDataFloat64x2ArrayCid,
-
- kInt32x4Cid,
- kFloat32x4Cid,
- kFloat64x2Cid,
-
- kTypeCid,
- kFunctionTypeCid,
- kTypeRefCid,
- kTypeParameterCid,
- kBoundedTypeCid,
- kLibraryPrefixCid,
-
- kJSRegExpCid,
- kUserTagCid,
- kStacktraceCid,
- kWeakPropertyCid,
- kCapabilityCid,
- ReceivePort::kClassId,
- SendPort::kClassId,
-
- kIllegalCid
- };
-
Class& cls = Class::Handle(Z);
- for (intptr_t i = 0; kExternallyAllocatedCids[i] != kIllegalCid; i++) {
- cls = isolate()->class_table()->At(kExternallyAllocatedCids[i]);
+ for (intptr_t cid = kInstanceCid; cid < kNumPredefinedCids; cid++) {
+ ASSERT(isolate()->class_table()->IsValidIndex(cid));
+ if (!isolate()->class_table()->HasValidClassAt(cid)) {
+ continue;
+ }
+ if ((cid == kDynamicCid) ||
+ (cid == kVoidCid) ||
+ (cid == kFreeListElement)) {
+ continue;
+ }
+ cls = isolate()->class_table()->At(cid);
AddInstantiatedClass(cls);
}
Dart_QualifiedFunctionName vm_entry_points[] = {
// Functions
{ "dart:async", "::", "_setScheduleImmediateClosure" },
- { "dart:core", "::", "_completeDeferredLoads"},
+ { "dart:core", "::", "_completeDeferredLoads" },
{ "dart:core", "AbstractClassInstantiationError",
"AbstractClassInstantiationError._create" },
{ "dart:core", "ArgumentError", "ArgumentError." },
@@ -483,6 +437,8 @@ void Precompiler::ProcessFunction(const Function& function) {
if (!error_.IsNull()) {
Jump(error_);
}
+ // Used in the JIT to save type-feedback across compilations.
+ function.ClearICDataArray();
} else {
if (FLAG_trace_precompiler) {
// This function was compiled from somewhere other than Precompiler,
@@ -510,7 +466,7 @@ void Precompiler::AddCalleesOf(const Function& function) {
for (intptr_t i = 0; i < table.Length(); i++) {
entry = table.At(i);
if (entry.IsFunction()) {
- target ^= table.At(i);
+ target ^= entry.raw();
AddFunction(target);
}
}
@@ -532,9 +488,8 @@ void Precompiler::AddCalleesOf(const Function& function) {
entry = pool.ObjectAt(i);
if (entry.IsICData()) {
call_site ^= entry.raw();
- if (call_site.NumberOfChecks() == 1) {
- // Probably a static call.
- target = call_site.GetTargetAt(0);
+ for (intptr_t j = 0; j < call_site.NumberOfChecks(); j++) {
+ target = call_site.GetTargetAt(j);
AddFunction(target);
if (!target.is_static()) {
// Super call (should not enqueue selector) or dynamic call with a
@@ -542,7 +497,8 @@ void Precompiler::AddCalleesOf(const Function& function) {
selector = call_site.target_name();
AddSelector(selector);
}
- } else {
+ }
+ if (call_site.NumberOfChecks() == 0) {
// A dynamic call.
selector = call_site.target_name();
AddSelector(selector);
@@ -563,7 +519,11 @@ void Precompiler::AddCalleesOf(const Function& function) {
} else if (entry.IsInstance()) {
// Const object, literal or args descriptor.
instance ^= entry.raw();
- AddConstObject(instance);
+ if (entry.IsAbstractType()) {
+ AddType(AbstractType::Cast(entry));
+ } else {
+ AddConstObject(instance);
+ }
} else if (entry.IsFunction()) {
// Local closure function.
target ^= entry.raw();
@@ -574,12 +534,99 @@ void Precompiler::AddCalleesOf(const Function& function) {
cls ^= target_code.owner();
AddInstantiatedClass(cls);
}
+ } else if (entry.IsTypeArguments()) {
+ AddTypeArguments(TypeArguments::Cast(entry));
}
}
}
}
+void Precompiler::AddTypesOf(const Class& cls) {
+ if (cls.IsNull()) return;
+ if (classes_to_retain_.Lookup(&cls) != NULL) return;
+ classes_to_retain_.Insert(&Class::ZoneHandle(Z, cls.raw()));
+
+ Array& interfaces = Array::Handle(Z, cls.interfaces());
+ AbstractType& type = AbstractType::Handle(Z);
+ for (intptr_t i = 0; i < interfaces.Length(); i++) {
+ type ^= interfaces.At(i);
+ AddType(type);
+ }
+
+ AddTypeArguments(TypeArguments::Handle(Z, cls.type_parameters()));
+
+ type = cls.super_type();
+ AddType(type);
+
+ type = cls.mixin();
+ AddType(type);
+
+ if (cls.IsTypedefClass()) {
+ AddTypesOf(Function::Handle(Z, cls.signature_function()));
+ }
+}
+
+
+void Precompiler::AddTypesOf(const Function& function) {
+ AbstractType& type = AbstractType::Handle(Z);
+ type = function.result_type();
+ AddType(type);
+ for (intptr_t i = 0; i < function.NumParameters(); i++) {
+ type = function.ParameterTypeAt(i);
+ AddType(type);
+ }
+}
+
+
+void Precompiler::AddType(const AbstractType& abstype) {
+ if (abstype.IsNull()) return;
+
+ if (types_to_retain_.Lookup(&abstype) != NULL) return;
+ types_to_retain_.Insert(&AbstractType::ZoneHandle(Z, abstype.raw()));
+
+ if (abstype.IsType()) {
+ const Type& type = Type::Cast(abstype);
+ const Class& cls = Class::Handle(Z, type.type_class());
+ AddTypesOf(cls);
+ const TypeArguments& vector = TypeArguments::Handle(Z, abstype.arguments());
+ AddTypeArguments(vector);
+ } else if (abstype.IsFunctionType()) {
+ const FunctionType& func_type = FunctionType::Cast(abstype);
+ const Class& cls = Class::Handle(Z, func_type.scope_class());
+ AddTypesOf(cls);
+ const Function& func = Function::Handle(Z, func_type.signature());
+ AddTypesOf(func);
+ const TypeArguments& vector = TypeArguments::Handle(Z, abstype.arguments());
+ AddTypeArguments(vector);
+ } else if (abstype.IsBoundedType()) {
+ AbstractType& type = AbstractType::Handle(Z);
+ type = BoundedType::Cast(abstype).type();
+ AddType(type);
+ type = BoundedType::Cast(abstype).bound();
+ AddType(type);
+ } else if (abstype.IsTypeRef()) {
+ AbstractType& type = AbstractType::Handle(Z);
+ type = TypeRef::Cast(abstype).type();
+ AddType(type);
+ }
+}
+
+
+void Precompiler::AddTypeArguments(const TypeArguments& args) {
+ if (args.IsNull()) return;
+
+ if (typeargs_to_retain_.Lookup(&args) != NULL) return;
+ typeargs_to_retain_.Insert(&TypeArguments::ZoneHandle(Z, args.raw()));
+
+ AbstractType& arg = AbstractType::Handle(Z);
+ for (intptr_t i = 0; i < args.Length(); i++) {
+ arg = args.TypeAt(i);
+ AddType(arg);
+ }
+}
+
+
void Precompiler::AddConstObject(const Instance& instance) {
const Class& cls = Class::Handle(Z, instance.clazz());
AddInstantiatedClass(cls);
@@ -590,6 +637,7 @@ void Precompiler::AddConstObject(const Instance& instance) {
Function::Handle(Z, Closure::Cast(instance).function());
ASSERT(func.is_static());
AddFunction(func);
+ AddTypeArguments(TypeArguments::Handle(Z, instance.GetTypeArguments()));
return;
}
@@ -600,6 +648,10 @@ void Precompiler::AddConstObject(const Instance& instance) {
// argument descriptors.
if (!instance.IsCanonical()) return;
+ if (cls.NumTypeArguments() > 0) {
+ AddTypeArguments(TypeArguments::Handle(Z, instance.GetTypeArguments()));
+ }
+
class ConstObjectVisitor : public ObjectPointerVisitor {
public:
ConstObjectVisitor(Precompiler* precompiler, Isolate* isolate) :
@@ -682,7 +734,7 @@ RawFunction* Precompiler::CompileStaticInitializer(const Field& field) {
ASSERT(field.is_static());
if (field.HasPrecompiledInitializer()) {
// TODO(rmacnak): Investigate why this happens for _enum_names.
- OS::Print("Warning: Ignoring repeated request for initializer for %s\n",
+ THR_Print("Warning: Ignoring repeated request for initializer for %s\n",
field.ToCString());
return Function::null();
}
@@ -1142,6 +1194,7 @@ void Precompiler::DropFunctions() {
if (retain) {
retained_functions.Add(function);
function.DropUncompiledImplicitClosureFunction();
+ AddTypesOf(function);
} else {
bool top_level = cls.IsTopLevel();
if (top_level &&
@@ -1173,8 +1226,10 @@ void Precompiler::DropFunctions() {
retained_functions = GrowableObjectArray::New();
for (intptr_t j = 0; j < closures.Length(); j++) {
function ^= closures.At(j);
- if (function.HasCode()) {
+ bool retain = function.HasCode();
+ if (retain) {
retained_functions.Add(function);
+ AddTypesOf(function);
} else {
dropped_function_count_++;
if (FLAG_trace_precompiler) {
@@ -1194,6 +1249,7 @@ void Precompiler::DropFields() {
Field& field = Field::Handle(Z);
GrowableObjectArray& retained_fields = GrowableObjectArray::Handle(Z);
String& name = String::Handle(Z);
+ AbstractType& type = AbstractType::Handle(Z);
for (intptr_t i = 0; i < libraries_.Length(); i++) {
lib ^= libraries_.At(i);
@@ -1211,6 +1267,8 @@ void Precompiler::DropFields() {
bool retain = fields_to_retain_.Lookup(&field) != NULL;
if (retain) {
retained_fields.Add(field);
+ type = field.type();
+ AddType(type);
} else {
bool top_level = cls.IsTopLevel();
if (top_level) {
@@ -1237,6 +1295,249 @@ void Precompiler::DropFields() {
}
+void Precompiler::DropTypes() {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Object& obj = Object::Handle(Z);
+ Array& arr = Array::Handle(Z);
+ GrowableObjectArray& retained_types = GrowableObjectArray::Handle(Z);
+ AbstractType& type = AbstractType::Handle(Z);
+
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+ while (it.HasNext()) {
+ cls = it.GetNextClass();
+ if (cls.IsDynamicClass()) {
+ continue; // class 'dynamic' is in the read-only VM isolate.
+ }
+ obj = cls.canonical_types();
+ if (!obj.IsArray()) {
+ // Class only has one type, keep it.
+ } else {
+ // Class has many types.
+ arr ^= obj.raw();
+ retained_types = GrowableObjectArray::New();
+
+ // Always keep the first one.
+ ASSERT(arr.Length() >= 1);
+ obj = arr.At(0);
+ retained_types.Add(obj);
+
+ for (intptr_t i = 1; i < arr.Length(); i++) {
+ obj = arr.At(i);
+ if (obj.IsNull()) {
+ continue;
+ }
+ type ^= obj.raw();
+ bool retain = types_to_retain_.Lookup(&type) != NULL;
+ if (retain) {
+ retained_types.Add(type);
+ } else {
+ dropped_type_count_++;
+ }
+ }
+ arr = Array::MakeArray(retained_types);
+ cls.set_canonical_types(arr);
+ }
+ }
+ }
+}
+
+
+void Precompiler::DropTypeArguments() {
+ const Array& typeargs_table =
+ Array::Handle(Z, I->object_store()->canonical_type_arguments());
+ GrowableObjectArray& retained_typeargs =
+ GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+ TypeArguments& typeargs = TypeArguments::Handle(Z);
+ for (intptr_t i = 0; i < (typeargs_table.Length() - 1); i++) {
+ typeargs ^= typeargs_table.At(i);
+ bool retain = typeargs_to_retain_.Lookup(&typeargs) != NULL;
+ if (retain) {
+ retained_typeargs.Add(typeargs);
+ } else {
+ dropped_typearg_count_++;
+ }
+ }
+
+ const intptr_t dict_size =
+ Utils::RoundUpToPowerOfTwo(retained_typeargs.Length() * 4 / 3);
+ const Array& new_table = Array::Handle(Z, Array::New(dict_size + 1));
+
+ Object& element = Object::Handle(Z);
+ for (intptr_t i = 0; i < retained_typeargs.Length(); i++) {
+ typeargs ^= retained_typeargs.At(i);
+ intptr_t hash = typeargs.Hash();
+ intptr_t index = hash & (dict_size - 1);
+ element = new_table.At(index);
+ while (!element.IsNull()) {
+ index = (index + 1) & (dict_size - 1);
+ element = new_table.At(index);
+ }
+ new_table.SetAt(index, typeargs);
+ }
+
+ const Smi& used = Smi::Handle(Z, Smi::New(retained_typeargs.Length()));
+ new_table.SetAt(dict_size, used);
+
+ I->object_store()->set_canonical_type_arguments(new_table);
+}
+
+
+void Precompiler::TraceTypesFromRetainedClasses() {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Array& members = Array::Handle(Z);
+
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+ while (it.HasNext()) {
+ cls = it.GetNextClass();
+ if (cls.IsDynamicClass()) {
+ continue; // class 'dynamic' is in the read-only VM isolate.
+ }
+
+ // The subclasses array is only needed for CHA.
+ cls.ClearDirectSubclasses();
+
+ bool retain = false;
+ members = cls.fields();
+ if (members.Length() > 0) {
+ retain = true;
+ }
+ members = cls.functions();
+ if (members.Length() > 0) {
+ retain = true;
+ }
+ if (cls.is_allocated()) {
+ retain = true;
+ }
+ if (cls.is_enum_class()) {
+ // Enum classes have live instances, so we cannot unregister
+ // them.
+ retain = true;
+ }
+ members = cls.constants();
+ if (members.Length() > 0) {
+ // --compile_all?
+ retain = true;
+ }
+
+ if (retain) {
+ AddTypesOf(cls);
+ }
+ }
+ }
+}
+
+
+void Precompiler::DropClasses() {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Array& members = Array::Handle(Z);
+ String& name = String::Handle(Z);
+
+#if defined(DEBUG)
+ {
+ // Force GC for allocation stats.
+ I->heap()->CollectAllGarbage();
+ }
+#endif
+
+ ClassTable* class_table = I->class_table();
+ intptr_t num_cids = class_table->NumCids();
+
+ for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) {
+ if (!class_table->IsValidIndex(cid)) continue;
+ if (!class_table->HasValidClassAt(cid)) continue;
+
+ cls = class_table->At(cid);
+ ASSERT(!cls.IsNull());
+
+ if (cls.IsTopLevel()) {
+ // Top-level classes are referenced directly from their library. They
+ // will only be removed as a consequence of an entire library being
+ // removed.
+ continue;
+ }
+ if (cls.is_enum_class()) {
+ // Enum classes have live instances, so we cannot unregister
+ // them.
+ continue;
+ }
+ members = cls.constants();
+ if (members.Length() > 0) {
+ // --compile_all?
+ continue;
+ }
+
+ bool retain = classes_to_retain_.Lookup(&cls) != NULL;
+ if (retain) {
+ continue;
+ }
+
+#if defined(DEBUG)
+ intptr_t instances =
+ class_table->StatsWithUpdatedSize(cid)->post_gc.new_count +
+ class_table->StatsWithUpdatedSize(cid)->post_gc.old_count;
+ if (instances != 0) {
+ FATAL2("Want to drop class %s, but it has %" Pd " instances\n",
+ cls.ToCString(),
+ instances);
+ }
+#endif
+
+ dropped_class_count_++;
+ if (FLAG_trace_precompiler) {
+ THR_Print("Precompilation dropping %" Pd " %s\n", cid, cls.ToCString());
+ }
+
+#if defined(DEBUG)
+ class_table->Unregister(cid);
+#endif
+ cls.set_id(kIllegalCid); // We check this when serializing.
+
+ lib = cls.library();
+ name = cls.DictionaryName();
+ lib.RemoveObject(cls, name);
+ }
+}
+
+
+void Precompiler::DropLibraries() {
+ const GrowableObjectArray& retained_libraries =
+ GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+ Library& lib = Library::Handle(Z);
+
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ lib.DropDependencies();
+ intptr_t entries = 0;
+ DictionaryIterator it(lib);
+ while (it.HasNext()) {
+ it.GetNext();
+ entries++;
+ }
+ bool retain = (entries > 0) || lib.is_dart_scheme();
+ if (retain) {
+ lib.set_index(retained_libraries.Length());
+ retained_libraries.Add(lib);
+ } else {
+ dropped_library_count_++;
+ lib.set_index(-1);
+ if (FLAG_trace_precompiler) {
+ THR_Print("Precompilation dropping %s\n", lib.ToCString());
+ }
+ }
+ }
+
+ I->object_store()->set_libraries(retained_libraries);
+ libraries_ = retained_libraries.raw();
+}
+
+
void Precompiler::BindStaticCalls() {
class BindStaticCallsVisitor : public FunctionVisitor {
public:

Powered by Google App Engine
This is Rietveld 408576698