Files
sdk/runtime/vm/compiler/cha.cc
T
Tess Strickland e8ddc0219f [vm] Abstract out internal-only cid ordering.
* Adds IsInternalOnlyCid, which replaces the old `cid < kInstanceCid`
  check.

* Adds kFirstInternalOnlyCid and kLastInternalOnlyCid, which should be
  used in places that loop over the internal-only cids.

* Adds ObjectComesBeforeOtherInternalOnlyClasses(), which can be used
  with COMPILE_ASSERT in places that assume kObjectCid immediately
  precedes the other internal-only cids.

* Replaces assumption in IsErrorId() that Instance immediately follows
  the internal-only cids with an assumption that the current last error
  cid is the same as kLastInternalOnlyCid.

* Separates out CLASS_LIST_NO_OBJECT_NOR_STRING_... into two pieces to
  make it clearer where to add new internal-only cids and where to add
  new Instance cids:

    * CLASS_LIST_INTERNAL_ONLY, which contains class ids for real
      classes that are VM internal, except for Object.

    * CLASS_LIST_INSTANCE_SINGLETONS, which contains class ids for
      subclasses of Instance that are not part of a separately handled
      group of cids.

TEST=Refactoring, so existing tests.

Change-Id: I9905d5928a592164d58de1f121b9ce669f2b3ce1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/210122
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
2021-08-13 13:27:41 +00:00

178 lines
5.6 KiB
C++

// Copyright (c) 2012, 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/compiler/cha.h"
#include "vm/class_table.h"
#include "vm/flags.h"
#include "vm/object.h"
#include "vm/raw_object.h"
#include "vm/visitor.h"
namespace dart {
void CHA::AddToGuardedClasses(const Class& cls, intptr_t subclass_count) {
for (intptr_t i = 0; i < guarded_classes_.length(); i++) {
if (guarded_classes_[i].cls->ptr() == cls.ptr()) {
return;
}
}
GuardedClassInfo info = {&Class::ZoneHandle(thread_->zone(), cls.ptr()),
subclass_count};
guarded_classes_.Add(info);
return;
}
bool CHA::IsGuardedClass(intptr_t cid) const {
for (intptr_t i = 0; i < guarded_classes_.length(); ++i) {
if (guarded_classes_[i].cls->id() == cid) return true;
}
return false;
}
bool CHA::HasSubclasses(const Class& cls) {
ASSERT(!cls.IsNull());
ASSERT(!IsInternalOnlyId(cls.id()));
// Can't track dependencies for classes on the VM heap since those are
// read-only.
// TODO(fschneider): Enable tracking of CHA dependent code for VM heap
// classes.
if (cls.InVMIsolateHeap()) return true;
if (cls.IsObjectClass()) {
// Class Object has subclasses, although we do not keep track of them.
return true;
}
Thread* thread = Thread::Current();
SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
const GrowableObjectArray& direct_subclasses =
GrowableObjectArray::Handle(cls.direct_subclasses());
return !direct_subclasses.IsNull() && (direct_subclasses.Length() > 0);
}
bool CHA::HasSubclasses(intptr_t cid) const {
const ClassTable& class_table = *thread_->isolate_group()->class_table();
Class& cls = Class::Handle(thread_->zone(), class_table.At(cid));
return HasSubclasses(cls);
}
bool CHA::ConcreteSubclasses(const Class& cls,
GrowableArray<intptr_t>* class_ids) {
if (cls.InVMIsolateHeap()) return false;
if (cls.IsObjectClass()) return false;
if (!cls.is_abstract()) {
class_ids->Add(cls.id());
}
// This is invoked from precompiler only, we can use unsafe version of
// Class::direct_subclasses getter.
ASSERT(FLAG_precompiled_mode);
const GrowableObjectArray& direct_subclasses =
GrowableObjectArray::Handle(cls.direct_subclasses_unsafe());
if (direct_subclasses.IsNull()) {
return true;
}
Class& subclass = Class::Handle();
for (intptr_t i = 0; i < direct_subclasses.Length(); i++) {
subclass ^= direct_subclasses.At(i);
if (!ConcreteSubclasses(subclass, class_ids)) {
return false;
}
}
return true;
}
bool CHA::IsImplemented(const Class& cls) {
// Can't track dependencies for classes on the VM heap since those are
// read-only.
// TODO(fschneider): Enable tracking of CHA dependent code for VM heap
// classes.
if (cls.InVMIsolateHeap()) return true;
return cls.is_implemented();
}
static intptr_t CountFinalizedSubclasses(Thread* thread, const Class& cls) {
intptr_t count = 0;
const GrowableObjectArray& cls_direct_subclasses =
GrowableObjectArray::Handle(thread->zone(), cls.direct_subclasses());
if (cls_direct_subclasses.IsNull()) return count;
Class& direct_subclass = Class::Handle(thread->zone());
for (intptr_t i = 0; i < cls_direct_subclasses.Length(); i++) {
direct_subclass ^= cls_direct_subclasses.At(i);
// Unfinalized classes are treated as non-existent for CHA purposes,
// as that means that no instance of that class exists at runtime.
if (!direct_subclass.is_finalized()) {
continue;
}
count += 1 + CountFinalizedSubclasses(thread, direct_subclass);
}
return count;
}
bool CHA::IsConsistentWithCurrentHierarchy() const {
for (intptr_t i = 0; i < guarded_classes_.length(); i++) {
const intptr_t subclass_count =
CountFinalizedSubclasses(thread_, *guarded_classes_[i].cls);
if (guarded_classes_[i].subclass_count != subclass_count) {
return false;
}
}
return true;
}
bool CHA::HasOverride(const Class& cls,
const String& function_name,
intptr_t* subclasses_count) {
// Can't track dependencies for classes on the VM heap since those are
// read-only.
// TODO(fschneider): Enable tracking of CHA dependent code for VM heap
// classes.
if (cls.InVMIsolateHeap()) return true;
// Subclasses of Object are not tracked by CHA. Safely assume that overrides
// exist.
if (cls.IsObjectClass()) {
return true;
}
SafepointReadRwLocker ml(thread_, thread_->isolate_group()->program_lock());
const GrowableObjectArray& cls_direct_subclasses =
GrowableObjectArray::Handle(thread_->zone(), cls.direct_subclasses());
if (cls_direct_subclasses.IsNull()) {
return false;
}
Class& direct_subclass = Class::Handle(thread_->zone());
for (intptr_t i = 0; i < cls_direct_subclasses.Length(); i++) {
direct_subclass ^= cls_direct_subclasses.At(i);
// Unfinalized classes are treated as non-existent for CHA purposes,
// as that means that no instance of that class exists at runtime.
if (!direct_subclass.is_finalized()) {
continue;
}
if (direct_subclass.LookupDynamicFunctionUnsafe(function_name) !=
Function::null()) {
return true;
}
if (HasOverride(direct_subclass, function_name, subclasses_count)) {
return true;
}
(*subclasses_count)++;
}
return false;
}
void CHA::RegisterDependencies(const Code& code) const {
for (intptr_t i = 0; i < guarded_classes_.length(); ++i) {
guarded_classes_[i].cls->RegisterCHACode(code);
}
}
} // namespace dart