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

Unified Diff: runtime/vm/class_finalizer.cc

Issue 2699853002: Sort class IDs before training AppJIT snapshots (Closed)
Patch Set: Add DeleteAllCode Created 3 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
« no previous file with comments | « runtime/vm/class_finalizer.h ('k') | runtime/vm/class_table.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/class_finalizer.cc
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 70b782ba647b31d54be3ed312506fb1b22da5321..6d88977e09f4c83e27c9e7590a9ad370a4f80d9f 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -6,13 +6,16 @@
#include "vm/code_generator.h"
#include "vm/flags.h"
+#include "vm/hash_table.h"
#include "vm/heap.h"
#include "vm/isolate.h"
#include "vm/longjump.h"
#include "vm/log.h"
#include "vm/object_store.h"
+#include "vm/program_visitor.h"
#include "vm/symbols.h"
#include "vm/timeline.h"
+#include "vm/type_table.h"
namespace dart {
@@ -3441,4 +3444,270 @@ void ClassFinalizer::VerifyImplicitFieldOffsets() {
#endif
}
+
+void ClassFinalizer::SortClasses() {
+ Thread* T = Thread::Current();
+ Zone* Z = T->zone();
+ Isolate* I = T->isolate();
+ ClassTable* table = I->class_table();
+ intptr_t num_cids = table->NumCids();
+ intptr_t* old_to_new_cid = new intptr_t[num_cids];
+ for (intptr_t cid = 0; cid < kNumPredefinedCids; cid++) {
+ old_to_new_cid[cid] = cid; // The predefined classes cannot change cids.
+ }
+ for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) {
+ old_to_new_cid[cid] = -1;
+ }
+
+ intptr_t next_new_cid = kNumPredefinedCids;
+ GrowableArray<intptr_t> dfs_stack;
+ Class& cls = Class::Handle(Z);
+ GrowableObjectArray& subclasses = GrowableObjectArray::Handle(Z);
+
+ // Object doesn't use its subclasses list.
+ for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) {
+ if (!table->HasValidClassAt(cid)) {
+ continue;
+ }
+ cls = table->At(cid);
+ if (cls.is_patch()) {
+ continue;
+ }
+ if (cls.SuperClass() == I->object_store()->object_class()) {
+ dfs_stack.Add(cid);
+ }
+ }
+
+ while (dfs_stack.length() > 0) {
+ intptr_t cid = dfs_stack.RemoveLast();
+ ASSERT(table->HasValidClassAt(cid));
+ cls = table->At(cid);
+ ASSERT(!cls.IsNull());
+ if (old_to_new_cid[cid] == -1) {
+ old_to_new_cid[cid] = next_new_cid++;
+ if (FLAG_trace_class_finalization) {
+ THR_Print("%" Pd ": %s, was %" Pd "\n", old_to_new_cid[cid],
+ cls.ToCString(), cid);
+ }
+ }
+ subclasses = cls.direct_subclasses();
+ if (!subclasses.IsNull()) {
+ for (intptr_t i = 0; i < subclasses.Length(); i++) {
+ cls ^= subclasses.At(i);
+ ASSERT(!cls.IsNull());
+ dfs_stack.Add(cls.id());
+ }
+ }
+ }
+
+ // Top-level classes, typedefs, patch classes, etc.
+ for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) {
+ if (old_to_new_cid[cid] == -1) {
+ old_to_new_cid[cid] = next_new_cid++;
+ if (FLAG_trace_class_finalization && table->HasValidClassAt(cid)) {
+ cls = table->At(cid);
+ THR_Print("%" Pd ": %s, was %" Pd "\n", old_to_new_cid[cid],
+ cls.ToCString(), cid);
+ }
+ }
+ }
+ ASSERT(next_new_cid == num_cids);
+
+ RemapClassIds(old_to_new_cid);
+ delete[] old_to_new_cid;
+ RehashTypes(); // Types use cid's as part of their hashes.
+}
+
+
+class CidRewriteVisitor : public ObjectVisitor {
+ public:
+ explicit CidRewriteVisitor(intptr_t* old_to_new_cids)
+ : old_to_new_cids_(old_to_new_cids) {}
+
+ intptr_t Map(intptr_t cid) {
+ ASSERT(cid != -1);
+ return old_to_new_cids_[cid];
+ }
+
+ void VisitObject(RawObject* obj) {
+ if (obj->IsClass()) {
+ RawClass* cls = Class::RawCast(obj);
+ cls->ptr()->id_ = Map(cls->ptr()->id_);
+ } else if (obj->IsField()) {
+ RawField* field = Field::RawCast(obj);
+ field->ptr()->guarded_cid_ = Map(field->ptr()->guarded_cid_);
+ field->ptr()->is_nullable_ = Map(field->ptr()->is_nullable_);
+ } else if (obj->IsTypeParameter()) {
+ RawTypeParameter* param = TypeParameter::RawCast(obj);
+ param->ptr()->parameterized_class_id_ =
+ Map(param->ptr()->parameterized_class_id_);
+ } else if (obj->IsType()) {
+ RawType* type = Type::RawCast(obj);
+ RawObject* id = type->ptr()->type_class_id_;
+ if (!id->IsHeapObject()) {
+ type->ptr()->type_class_id_ =
+ Smi::New(Map(Smi::Value(Smi::RawCast(id))));
+ }
+ } else {
+ intptr_t old_cid = obj->GetClassId();
+ intptr_t new_cid = Map(old_cid);
+ if (old_cid != new_cid) {
+ // Don't touch objects that are unchanged. In particular, Instructions,
+ // which are write-protected.
+ obj->SetClassId(new_cid);
+ }
+ }
+ }
+
+ private:
+ intptr_t* old_to_new_cids_;
+};
+
+
+void ClassFinalizer::RemapClassIds(intptr_t* old_to_new_cid) {
+ Isolate* I = Thread::Current()->isolate();
+
+ // Code, ICData, allocation stubs have now-invalid cids.
+ ClearAllCode();
+
+ {
+ HeapIterationScope his;
+ I->set_remapping_cids(true);
+
+ // Update the class table. Do it before rewriting cids in headers, as the
+ // heap walkers load an object's size *after* calling the visitor.
+ I->class_table()->Remap(old_to_new_cid);
+
+ // Rewrite cids in headers and cids in Classes, Fields, Types and
+ // TypeParameters.
+ {
+ CidRewriteVisitor visitor(old_to_new_cid);
+ I->heap()->VisitObjects(&visitor);
+ }
+ I->set_remapping_cids(false);
+ }
+
+#if defined(DEBUG)
+ I->class_table()->Validate();
+ I->heap()->Verify();
+#endif
+}
+
+
+class ClearTypeHashVisitor : public ObjectVisitor {
+ public:
+ explicit ClearTypeHashVisitor(Zone* zone)
+ : type_param_(TypeParameter::Handle(zone)),
+ type_(Type::Handle(zone)),
+ type_args_(TypeArguments::Handle(zone)),
+ bounded_type_(BoundedType::Handle(zone)) {}
+
+ void VisitObject(RawObject* obj) {
+ if (obj->IsTypeParameter()) {
+ type_param_ ^= obj;
+ type_param_.SetHash(0);
+ } else if (obj->IsType()) {
+ type_ ^= obj;
+ type_.SetHash(0);
+ } else if (obj->IsBoundedType()) {
+ bounded_type_ ^= obj;
+ bounded_type_.SetHash(0);
+ } else if (obj->IsTypeArguments()) {
+ type_args_ ^= obj;
+ type_args_.SetHash(0);
+ }
+ }
+
+ private:
+ TypeParameter& type_param_;
+ Type& type_;
+ TypeArguments& type_args_;
+ BoundedType& bounded_type_;
+};
+
+
+void ClassFinalizer::RehashTypes() {
+ Thread* T = Thread::Current();
+ Zone* Z = T->zone();
+ Isolate* I = T->isolate();
+
+ // Clear all cached hash values.
+ {
+ HeapIterationScope his;
+ ClearTypeHashVisitor visitor(Z);
+ I->heap()->VisitObjects(&visitor);
+ }
+
+ // Rehash the canonical Types table.
+ ObjectStore* object_store = I->object_store();
+ GrowableObjectArray& types =
+ GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+ Array& types_array = Array::Handle(Z);
+ Type& type = Type::Handle(Z);
+ {
+ CanonicalTypeSet types_table(Z, object_store->canonical_types());
+ types_array = HashTables::ToArray(types_table, false);
+ for (intptr_t i = 0; i < types_array.Length(); i++) {
+ type ^= types_array.At(i);
+ types.Add(type);
+ }
+ types_table.Release();
+ }
+
+ intptr_t dict_size = Utils::RoundUpToPowerOfTwo(types.Length() * 4 / 3);
+ types_array = HashTables::New<CanonicalTypeSet>(dict_size, Heap::kOld);
+ CanonicalTypeSet types_table(Z, types_array.raw());
+ for (intptr_t i = 0; i < types.Length(); i++) {
+ type ^= types.At(i);
+ bool present = types_table.Insert(type);
+ ASSERT(!present || type.IsRecursive());
+ }
+ object_store->set_canonical_types(types_table.Release());
+
+ // Rehash the canonical TypeArguments table.
+ Array& typeargs_array = Array::Handle(Z);
+ GrowableObjectArray& typeargs =
+ GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+ TypeArguments& typearg = TypeArguments::Handle(Z);
+ {
+ CanonicalTypeArgumentsSet typeargs_table(
+ Z, object_store->canonical_type_arguments());
+ typeargs_array = HashTables::ToArray(typeargs_table, false);
+ for (intptr_t i = 0; i < typeargs_array.Length(); i++) {
+ typearg ^= typeargs_array.At(i);
+ typeargs.Add(typearg);
+ }
+ typeargs_table.Release();
+ }
+
+ dict_size = Utils::RoundUpToPowerOfTwo(typeargs.Length() * 4 / 3);
+ typeargs_array =
+ HashTables::New<CanonicalTypeArgumentsSet>(dict_size, Heap::kOld);
+ CanonicalTypeArgumentsSet typeargs_table(Z, typeargs_array.raw());
+ for (intptr_t i = 0; i < typeargs.Length(); i++) {
+ typearg ^= typeargs.At(i);
+ bool present = typeargs_table.Insert(typearg);
+ ASSERT(!present || typearg.IsRecursive());
+ }
+ object_store->set_canonical_type_arguments(typeargs_table.Release());
+}
+
+
+void ClassFinalizer::ClearAllCode() {
+ class ClearCodeFunctionVisitor : public FunctionVisitor {
+ void Visit(const Function& function) {
+ function.ClearCode();
+ function.ClearICDataArray();
+ }
+ };
+ ClearCodeFunctionVisitor function_visitor;
+ ProgramVisitor::VisitFunctions(&function_visitor);
+
+ class ClearCodeClassVisitor : public ClassVisitor {
+ void Visit(const Class& cls) { cls.DisableAllocationStub(); }
+ };
+ ClearCodeClassVisitor class_visitor;
+ ProgramVisitor::VisitClasses(&class_visitor);
+}
+
} // namespace dart
« no previous file with comments | « runtime/vm/class_finalizer.h ('k') | runtime/vm/class_table.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698