[vm, compiler] Discover the sole implementation of an interface when it is a different class than the interface.

TEST=ci
Change-Id: Ibeb83f1099a9dfdeeaee69814739bff84617c1fb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/252243
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2022-07-26 17:33:37 +00:00 committed by Commit Bot
parent 955f1e90ec
commit 139d9216ad
13 changed files with 298 additions and 110 deletions

View file

@ -330,6 +330,7 @@ class ClassSerializationCluster : public SerializationCluster {
if (s->kind() != Snapshot::kFullAOT) {
s->WriteTokenPosition(cls->untag()->token_pos_);
s->WriteTokenPosition(cls->untag()->end_token_pos_);
s->WriteCid(cls->untag()->implementor_cid_);
}
s->Write<uint32_t>(cls->untag()->state_bits_);
@ -426,6 +427,7 @@ class ClassDeserializationCluster : public DeserializationCluster {
ASSERT(d_->kind() != Snapshot::kFullAOT);
cls->untag()->token_pos_ = d.ReadTokenPosition();
cls->untag()->end_token_pos_ = d.ReadTokenPosition();
cls->untag()->implementor_cid_ = d.ReadCid();
#endif // !defined(DART_PRECOMPILED_RUNTIME)
cls->untag()->state_bits_ = d.Read<uint32_t>();
@ -469,6 +471,7 @@ class ClassDeserializationCluster : public DeserializationCluster {
ASSERT(d_->kind() != Snapshot::kFullAOT);
cls->untag()->token_pos_ = d.ReadTokenPosition();
cls->untag()->end_token_pos_ = d.ReadTokenPosition();
cls->untag()->implementor_cid_ = d.ReadCid();
#endif // !defined(DART_PRECOMPILED_RUNTIME)
cls->untag()->state_bits_ = d.Read<uint32_t>();

View file

@ -302,6 +302,7 @@ void ClassFinalizer::VerifyBootstrapClasses() {
err.ToErrorCString());
OS::Exit(255);
}
if (FLAG_trace_class_finalization) {
OS::PrintErr("VerifyBootstrapClasses END.\n");
}
@ -1091,7 +1092,7 @@ void ClassFinalizer::RegisterClassInHierarchy(Zone* zone, const Class& cls) {
// Add this class as an implementor to the implemented interface's type
// classes.
const auto& interfaces = Array::Handle(zone, cls.interfaces());
auto& interfaces = Array::Handle(zone, cls.interfaces());
const intptr_t mixin_index =
cls.is_transformed_mixin_application() ? interfaces.Length() - 1 : -1;
for (intptr_t i = 0; i < interfaces.Length(); ++i) {
@ -1100,6 +1101,25 @@ void ClassFinalizer::RegisterClassInHierarchy(Zone* zone, const Class& cls) {
MarkImplemented(zone, other_cls);
other_cls.AddDirectImplementor(cls, /* is_mixin = */ i == mixin_index);
}
// Propogate known concrete implementors to interfaces.
if (!cls.is_abstract()) {
GrowableArray<const Class*> worklist;
worklist.Add(&cls);
while (!worklist.is_empty()) {
const Class& implemented = *worklist.RemoveLast();
if (!implemented.NoteImplementor(cls)) continue;
type = implemented.super_type();
if (!type.IsNull()) {
worklist.Add(&Class::Handle(zone, implemented.SuperClass()));
}
interfaces = implemented.interfaces();
for (intptr_t i = 0; i < interfaces.Length(); i++) {
type ^= interfaces.At(i);
worklist.Add(&Class::Handle(zone, type.type_class()));
}
}
}
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
@ -1493,6 +1513,7 @@ class CidRewriteVisitor : public ObjectVisitor {
return;
}
cls->untag()->id_ = Map(old_cid);
cls->untag()->implementor_cid_ = Map(cls->untag()->implementor_cid_);
} else if (obj->IsField()) {
FieldPtr field = Field::RawCast(obj);
field->untag()->guarded_cid_ = Map(field->untag()->guarded_cid_);

View file

@ -108,12 +108,13 @@ bool AotCallSpecializer::TryCreateICDataForUniqueTarget(
}
const Class& cls = Class::Handle(Z, target_function.Owner());
if (CHA::IsImplemented(cls) || CHA::HasSubclasses(cls)) {
intptr_t implementor_cid = kIllegalCid;
if (!CHA::HasSingleConcreteImplementation(cls, &implementor_cid)) {
return false;
}
call->SetTargets(
CallTargets::CreateMonomorphic(Z, cls.id(), target_function));
CallTargets::CreateMonomorphic(Z, implementor_cid, target_function));
ASSERT(call->Targets().IsMonomorphic());
// If we know that the only noSuchMethod is Object.noSuchMethod then

View file

@ -768,38 +768,12 @@ intptr_t CompileType::ToNullableCid() {
cid_ = kSentinelCid;
} else if (type_->IsFunctionType() || type_->IsDartFunctionType()) {
cid_ = kClosureCid;
} else if (type_->IsDoubleType()) {
cid_ = kDoubleCid; // double's only implementor is _Double.
} else if (type_->IsFloat32x4Type()) {
cid_ = kFloat32x4Cid; // Float32x4's only implementor is _Float32x4.
} else if (type_->IsFloat64x2Type()) {
cid_ = kFloat64x2Cid; // Float64x2's only implementor is _Float64x2.
} else if (type_->IsInt32x4Type()) {
cid_ = kInt32x4Cid; // Int32x4's only implementor is _Int32x4.
} else if (type_->type_class_id() != kIllegalCid) {
const Class& type_class = Class::Handle(type_->type_class());
Thread* thread = Thread::Current();
CHA& cha = thread->compiler_state().cha();
// Don't infer a cid from an abstract type since there can be multiple
// compatible classes with different cids.
if (!type_class.is_abstract() && !CHA::IsImplemented(type_class) &&
!CHA::HasSubclasses(type_class)) {
if (type_class.IsPrivate()) {
// Type of a private class cannot change through later loaded libs.
cid_ = type_class.id();
} else if (FLAG_use_cha_deopt ||
thread->isolate_group()->all_classes_finalized()) {
if (FLAG_trace_cha) {
THR_Print(" **(CHA) Compile type not subclassed: %s\n",
type_class.ToCString());
}
if (FLAG_use_cha_deopt) {
cha.AddToGuardedClasses(type_class, /*subclass_count=*/0);
}
cid_ = type_class.id();
} else {
cid_ = kDynamicCid;
}
intptr_t implementation_cid = kIllegalCid;
if (CHA::HasSingleConcreteImplementation(type_class,
&implementation_cid)) {
cid_ = implementation_cid;
} else {
cid_ = kDynamicCid;
}

View file

@ -1102,39 +1102,20 @@ BoolPtr CallSpecializer::InstanceOfAsBool(
}
// Returns true if checking against this type is a direct class id comparison.
bool CallSpecializer::TypeCheckAsClassEquality(const AbstractType& type) {
bool CallSpecializer::TypeCheckAsClassEquality(const AbstractType& type,
intptr_t* type_cid) {
*type_cid = kIllegalCid;
ASSERT(type.IsFinalized());
// Requires CHA.
if (!type.IsInstantiated()) return false;
// Function types have different type checking rules.
if (type.IsFunctionType()) return false;
const Class& type_class = Class::Handle(type.type_class());
// Could be an interface check?
if (CHA::IsImplemented(type_class)) return false;
// Check if there are subclasses.
if (CHA::HasSubclasses(type_class)) {
if (!CHA::HasSingleConcreteImplementation(type_class, type_cid)) {
return false;
}
// Private classes cannot be subclassed by later loaded libs.
if (!type_class.IsPrivate()) {
// In AOT mode we can't use CHA deoptimizations.
ASSERT(!CompilerState::Current().is_aot() || !FLAG_use_cha_deopt);
if (FLAG_use_cha_deopt || isolate_group()->all_classes_finalized()) {
if (FLAG_trace_cha) {
THR_Print(
" **(CHA) Typecheck as class equality since no "
"subclasses: %s\n",
type_class.ToCString());
}
if (FLAG_use_cha_deopt) {
thread()->compiler_state().cha().AddToGuardedClasses(
type_class, /*subclass_count=*/0);
}
} else {
return false;
}
}
const intptr_t num_type_args = type_class.NumTypeArguments();
if (num_type_args > 0) {
// Only raw types can be directly compared, thus disregarding type
@ -1242,10 +1223,10 @@ void CallSpecializer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
return;
}
if (TypeCheckAsClassEquality(type)) {
intptr_t type_cid;
if (TypeCheckAsClassEquality(type, &type_cid)) {
LoadClassIdInstr* left_cid = new (Z) LoadClassIdInstr(new (Z) Value(left));
InsertBefore(call, left_cid, NULL, FlowGraph::kValue);
const intptr_t type_cid = Class::Handle(Z, type.type_class()).id();
ConstantInstr* cid =
flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid)));

View file

@ -144,7 +144,7 @@ class CallSpecializer : public FlowGraphVisitor {
const bool should_clone_fields_;
private:
bool TypeCheckAsClassEquality(const AbstractType& type);
bool TypeCheckAsClassEquality(const AbstractType& type, intptr_t* type_cid);
// Insert a Smi check if needed.
void AddCheckSmi(Definition* to_check,

View file

@ -4,7 +4,9 @@
#include "vm/compiler/cha.h"
#include "vm/class_table.h"
#include "vm/compiler/compiler_state.h"
#include "vm/flags.h"
#include "vm/log.h"
#include "vm/object.h"
#include "vm/raw_object.h"
#include "vm/visitor.h"
@ -12,15 +14,36 @@
namespace dart {
void CHA::AddToGuardedClasses(const Class& cls, intptr_t subclass_count) {
ASSERT(subclass_count >= 0);
for (intptr_t i = 0; i < guarded_classes_.length(); i++) {
if (guarded_classes_[i].cls->ptr() == cls.ptr()) {
// Was added as an interface guard.
if (guarded_classes_[i].subclass_count == -1) {
guarded_classes_[i].subclass_count = subclass_count;
}
return;
}
}
GuardedClassInfo info = {&Class::ZoneHandle(thread_->zone(), cls.ptr()),
subclass_count};
subclass_count, kIllegalCid};
guarded_classes_.Add(info);
}
void CHA::AddToGuardedInterfaces(const Class& cls, intptr_t implementor_cid) {
ASSERT(implementor_cid != kIllegalCid);
ASSERT(implementor_cid != kDynamicCid);
for (intptr_t i = 0; i < guarded_classes_.length(); i++) {
if (guarded_classes_[i].cls->ptr() == cls.ptr()) {
// Was added as a subclass guard.
if (guarded_classes_[i].implementor_cid == kIllegalCid) {
guarded_classes_[i].implementor_cid = implementor_cid;
}
return;
}
}
GuardedClassInfo info = {&Class::ZoneHandle(thread_->zone(), cls.ptr()), -1,
implementor_cid};
guarded_classes_.Add(info);
return;
}
bool CHA::IsGuardedClass(intptr_t cid) const {
@ -93,6 +116,33 @@ bool CHA::IsImplemented(const Class& cls) {
return cls.is_implemented();
}
bool CHA::HasSingleConcreteImplementation(const Class& interface,
intptr_t* implementation_cid) {
intptr_t cid = interface.implementor_cid();
if ((cid == kIllegalCid) || (cid == kDynamicCid)) {
// No implementations / multiple implementations.
*implementation_cid = kDynamicCid;
return false;
}
Thread* thread = Thread::Current();
if (FLAG_use_cha_deopt || thread->isolate_group()->all_classes_finalized()) {
if (FLAG_trace_cha) {
THR_Print(" **(CHA) Type has one implementation: %s\n",
interface.ToCString());
}
if (FLAG_use_cha_deopt) {
CHA& cha = thread->compiler_state().cha();
cha.AddToGuardedInterfaces(interface, cid);
}
*implementation_cid = cid;
return true;
} else {
*implementation_cid = kDynamicCid;
return false;
}
}
static intptr_t CountFinalizedSubclasses(Thread* thread, const Class& cls) {
intptr_t count = 0;
const GrowableObjectArray& cls_direct_subclasses =
@ -114,10 +164,19 @@ static intptr_t CountFinalizedSubclasses(Thread* thread, const Class& cls) {
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;
if (guarded_classes_[i].subclass_count != -1) {
intptr_t current_subclass_count =
CountFinalizedSubclasses(thread_, *guarded_classes_[i].cls);
if (guarded_classes_[i].subclass_count != current_subclass_count) {
return false; // New subclass appeared during compilation.
}
}
if (guarded_classes_[i].implementor_cid != kIllegalCid) {
intptr_t current_implementor_cid =
guarded_classes_[i].cls->implementor_cid();
if (guarded_classes_[i].implementor_cid != current_implementor_cid) {
return false; // New implementor appeared during compilation.
}
}
}
return true;

View file

@ -37,9 +37,15 @@ class CHA : public ValueObject {
static bool ConcreteSubclasses(const Class& cls,
GrowableArray<intptr_t>* class_ids);
// Return true if the class is implemented by some other class.
// Return true if the class is implemented by some other class that is not a
// subclass.
static bool IsImplemented(const Class& cls);
// Return true if there is only one concrete class that implements
// 'interface'.
static bool HasSingleConcreteImplementation(const Class& interface,
intptr_t* implementation_cid);
// Returns true if any subclass of 'cls' contains the function.
// If no override was found subclass_count would contain total count of
// finalized subclasses that CHA looked at.
@ -49,10 +55,12 @@ class CHA : public ValueObject {
const String& function_name,
intptr_t* subclass_count);
// Adds class 'cls' to the list of guarded classes, deoptimization occurs
// if any of those classes gets subclassed through later loaded/finalized
// libraries. Only classes that were used for CHA optimizations are added.
// Adds class 'cls' to the list of guarded classes / interfaces.
// Deoptimization occurs if any of those classes gets subclassed or
// implemented through later loaded/finalized libraries. Only classes that
// were used for CHA optimizations are added.
void AddToGuardedClasses(const Class& cls, intptr_t subclass_count);
void AddToGuardedInterfaces(const Class& cls, intptr_t implementor_cid);
// When compiling in background we need to check that no new finalized
// subclasses were added to guarded classes.
@ -74,6 +82,12 @@ class CHA : public ValueObject {
// Used to validate correctness of background compilation: if
// any subclasses were added we will discard compiled code.
intptr_t subclass_count;
// Value of implementor_cid that this class had at the moment
// when CHA made the first decision based on this class.
// Used to validate correctness of background compilation: if
// any implementors were added we will discard compiled code.
intptr_t implementor_cid;
};
GrowableArray<GuardedClassInfo> guarded_classes_;

View file

@ -119,10 +119,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
52;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
88;
92;
static constexpr dart::compiler::target::word Class_super_type_offset = 44;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 100;
Class_host_type_arguments_field_offset_in_words_offset = 104;
static constexpr dart::compiler::target::word
SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 20;
@ -583,7 +583,7 @@ static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
static constexpr dart::compiler::target::word Array_header_size = 12;
static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
static constexpr dart::compiler::target::word Class_InstanceSize = 112;
static constexpr dart::compiler::target::word Class_InstanceSize = 116;
static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
static constexpr dart::compiler::target::word ClosureData_InstanceSize = 20;
static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
@ -780,10 +780,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
104;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
164;
168;
static constexpr dart::compiler::target::word Class_super_type_offset = 88;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 176;
Class_host_type_arguments_field_offset_in_words_offset = 180;
static constexpr dart::compiler::target::word
SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 40;
@ -1446,10 +1446,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
52;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
88;
92;
static constexpr dart::compiler::target::word Class_super_type_offset = 44;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 100;
Class_host_type_arguments_field_offset_in_words_offset = 104;
static constexpr dart::compiler::target::word
SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 20;
@ -1907,7 +1907,7 @@ static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
static constexpr dart::compiler::target::word Array_header_size = 12;
static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
static constexpr dart::compiler::target::word Class_InstanceSize = 112;
static constexpr dart::compiler::target::word Class_InstanceSize = 116;
static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
static constexpr dart::compiler::target::word ClosureData_InstanceSize = 20;
static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
@ -2104,10 +2104,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
104;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
164;
168;
static constexpr dart::compiler::target::word Class_super_type_offset = 88;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 176;
Class_host_type_arguments_field_offset_in_words_offset = 180;
static constexpr dart::compiler::target::word
SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 40;
@ -2771,10 +2771,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
56;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
92;
96;
static constexpr dart::compiler::target::word Class_super_type_offset = 48;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 104;
Class_host_type_arguments_field_offset_in_words_offset = 108;
static constexpr dart::compiler::target::word
SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 24;
@ -3437,10 +3437,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
56;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
92;
96;
static constexpr dart::compiler::target::word Class_super_type_offset = 48;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 104;
Class_host_type_arguments_field_offset_in_words_offset = 108;
static constexpr dart::compiler::target::word
SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 24;
@ -4104,10 +4104,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
52;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
88;
92;
static constexpr dart::compiler::target::word Class_super_type_offset = 44;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 100;
Class_host_type_arguments_field_offset_in_words_offset = 104;
static constexpr dart::compiler::target::word
SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 20;
@ -4570,7 +4570,7 @@ static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
static constexpr dart::compiler::target::word Array_header_size = 12;
static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
static constexpr dart::compiler::target::word Class_InstanceSize = 112;
static constexpr dart::compiler::target::word Class_InstanceSize = 116;
static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
static constexpr dart::compiler::target::word ClosureData_InstanceSize = 20;
static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
@ -4767,10 +4767,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
104;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
164;
168;
static constexpr dart::compiler::target::word Class_super_type_offset = 88;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 176;
Class_host_type_arguments_field_offset_in_words_offset = 180;
static constexpr dart::compiler::target::word
SharedClassTable_class_heap_stats_table_offset = 0;
static constexpr dart::compiler::target::word Closure_context_offset = 40;
@ -5433,10 +5433,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
48;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
84;
88;
static constexpr dart::compiler::target::word Class_super_type_offset = 40;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 96;
Class_host_type_arguments_field_offset_in_words_offset = 100;
static constexpr dart::compiler::target::word Closure_context_offset = 20;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 12;
@ -5892,7 +5892,7 @@ static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
static constexpr dart::compiler::target::word Array_header_size = 12;
static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
static constexpr dart::compiler::target::word Class_InstanceSize = 108;
static constexpr dart::compiler::target::word Class_InstanceSize = 112;
static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
static constexpr dart::compiler::target::word ClosureData_InstanceSize = 20;
static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
@ -6086,10 +6086,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
96;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
156;
160;
static constexpr dart::compiler::target::word Class_super_type_offset = 80;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 168;
Class_host_type_arguments_field_offset_in_words_offset = 172;
static constexpr dart::compiler::target::word Closure_context_offset = 40;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 24;
@ -6744,10 +6744,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
48;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
84;
88;
static constexpr dart::compiler::target::word Class_super_type_offset = 40;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 96;
Class_host_type_arguments_field_offset_in_words_offset = 100;
static constexpr dart::compiler::target::word Closure_context_offset = 20;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 12;
@ -7200,7 +7200,7 @@ static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
static constexpr dart::compiler::target::word Array_header_size = 12;
static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
static constexpr dart::compiler::target::word Class_InstanceSize = 108;
static constexpr dart::compiler::target::word Class_InstanceSize = 112;
static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
static constexpr dart::compiler::target::word ClosureData_InstanceSize = 20;
static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
@ -7394,10 +7394,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
96;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
156;
160;
static constexpr dart::compiler::target::word Class_super_type_offset = 80;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 168;
Class_host_type_arguments_field_offset_in_words_offset = 172;
static constexpr dart::compiler::target::word Closure_context_offset = 40;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 24;
@ -8053,10 +8053,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
52;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
88;
92;
static constexpr dart::compiler::target::word Class_super_type_offset = 44;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 100;
Class_host_type_arguments_field_offset_in_words_offset = 104;
static constexpr dart::compiler::target::word Closure_context_offset = 24;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 16;
@ -8519,7 +8519,7 @@ static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
static constexpr dart::compiler::target::word Array_header_size = 16;
static constexpr dart::compiler::target::word Bool_InstanceSize = 16;
static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
static constexpr dart::compiler::target::word Class_InstanceSize = 112;
static constexpr dart::compiler::target::word Class_InstanceSize = 120;
static constexpr dart::compiler::target::word Closure_InstanceSize = 32;
static constexpr dart::compiler::target::word ClosureData_InstanceSize = 24;
static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 16;
@ -8711,10 +8711,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
52;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
88;
92;
static constexpr dart::compiler::target::word Class_super_type_offset = 44;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 100;
Class_host_type_arguments_field_offset_in_words_offset = 104;
static constexpr dart::compiler::target::word Closure_context_offset = 24;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 16;
@ -9178,7 +9178,7 @@ static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
static constexpr dart::compiler::target::word Array_header_size = 16;
static constexpr dart::compiler::target::word Bool_InstanceSize = 16;
static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
static constexpr dart::compiler::target::word Class_InstanceSize = 112;
static constexpr dart::compiler::target::word Class_InstanceSize = 120;
static constexpr dart::compiler::target::word Closure_InstanceSize = 32;
static constexpr dart::compiler::target::word ClosureData_InstanceSize = 24;
static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 16;
@ -9370,10 +9370,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
48;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
84;
88;
static constexpr dart::compiler::target::word Class_super_type_offset = 40;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 96;
Class_host_type_arguments_field_offset_in_words_offset = 100;
static constexpr dart::compiler::target::word Closure_context_offset = 20;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 12;
@ -9831,7 +9831,7 @@ static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
static constexpr dart::compiler::target::word Array_header_size = 12;
static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
static constexpr dart::compiler::target::word Class_InstanceSize = 108;
static constexpr dart::compiler::target::word Class_InstanceSize = 112;
static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
static constexpr dart::compiler::target::word ClosureData_InstanceSize = 20;
static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
@ -10025,10 +10025,10 @@ static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
96;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
156;
160;
static constexpr dart::compiler::target::word Class_super_type_offset = 80;
static constexpr dart::compiler::target::word
Class_host_type_arguments_field_offset_in_words_offset = 168;
Class_host_type_arguments_field_offset_in_words_offset = 172;
static constexpr dart::compiler::target::word Closure_context_offset = 40;
static constexpr dart::compiler::target::word
Closure_delayed_type_arguments_offset = 24;

View file

@ -1394,6 +1394,13 @@ class FinalizeVMIsolateVisitor : public ObjectVisitor {
Object::SetCachedHashIfNotSet(obj, counter_);
}
}
#endif
#if !defined(DART_PRECOMPILED_RUNTIME)
if (obj->IsClass()) {
// Won't be able to update read-only VM isolate classes if implementors
// are discovered later.
static_cast<ClassPtr>(obj)->untag()->implementor_cid_ = kDynamicCid;
}
#endif
}
}
@ -2984,6 +2991,7 @@ ClassPtr Class::New(IsolateGroup* isolate_group, bool register_class) {
target_next_field_offset);
COMPILE_ASSERT((FakeObject::kClassId != kInstanceCid));
result.set_id(FakeObject::kClassId);
NOT_IN_PRECOMPILED(result.set_implementor_cid(kIllegalCid));
result.set_num_type_arguments_unsafe(0);
result.set_num_native_fields(0);
result.set_state_bits(0);
@ -4741,6 +4749,7 @@ ClassPtr Class::NewCommon(intptr_t index) {
result.set_next_field_offset(host_next_field_offset,
target_next_field_offset);
result.set_id(index);
NOT_IN_PRECOMPILED(result.set_implementor_cid(kIllegalCid));
result.set_num_type_arguments_unsafe(kUnknownNumTypeArguments);
result.set_num_native_fields(0);
result.set_state_bits(0);
@ -4826,6 +4835,7 @@ ClassPtr Class::NewNativeWrapper(const Library& library,
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
cls.set_is_synthesized_class();
NOT_IN_PRECOMPILED(cls.set_implementor_cid(kDynamicCid));
library.AddClass(cls);
return cls.ptr();
} else {
@ -5147,6 +5157,27 @@ void Class::set_end_token_pos(TokenPosition token_pos) const {
ASSERT(!token_pos.IsClassifying());
StoreNonPointer(&untag()->end_token_pos_, token_pos);
}
void Class::set_implementor_cid(intptr_t value) const {
ASSERT(value >= 0 && value < std::numeric_limits<classid_t>::max());
StoreNonPointer(&untag()->implementor_cid_, value);
}
bool Class::NoteImplementor(const Class& implementor) const {
ASSERT(!implementor.is_abstract());
ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
if (implementor_cid() == kDynamicCid) {
return false;
} else if (implementor_cid() == implementor.id()) {
return false;
} else if (implementor_cid() == kIllegalCid) {
set_implementor_cid(implementor.id());
return true; // None -> One
} else {
set_implementor_cid(kDynamicCid);
return true; // One -> Many
}
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
int32_t Class::SourceFingerprint() const {

View file

@ -1110,6 +1110,19 @@ class Class : public Object {
StoreNonPointer(&untag()->id_, value);
}
static intptr_t id_offset() { return OFFSET_OF(UntaggedClass, id_); }
#if !defined(DART_PRECOMPILED_RUNTIME)
// If the interface of this class has a single concrete implementation, either
// via `extends` or by `implements`, returns its CID.
// If it has no implementation, returns kIllegalCid.
// If it has more than one implementation, returns kDynamicCid.
intptr_t implementor_cid() const { return untag()->implementor_cid_; }
// Returns true if the implementor tracking state changes and so must be
// propagated to this class's superclass and interfaces.
bool NoteImplementor(const Class& implementor) const;
#endif
static intptr_t num_type_arguments_offset() {
return OFFSET_OF(UntaggedClass, num_type_arguments_);
}
@ -1531,6 +1544,9 @@ class Class : public Object {
return RoundedAllocationSize(sizeof(UntaggedClass));
}
// Returns true if any class implements this interface via `implements`.
// Returns false if all possible implementations of this interface must be
// instances of this class or its subclasses.
bool is_implemented() const { return ImplementedBit::decode(state_bits()); }
void set_is_implemented() const;
void set_is_implemented_unsafe() const;
@ -1874,6 +1890,7 @@ class Class : public Object {
void set_user_name(const String& value) const;
const char* GenerateUserVisibleName() const;
void set_state_bits(intptr_t bits) const;
void set_implementor_cid(intptr_t value) const;
FunctionPtr CreateInvocationDispatcher(const String& target_name,
const Array& args_desc,

View file

@ -5358,6 +5358,91 @@ class X extends E {}
EXPECT(class_a_sub.implements_finalizable());
}
TEST_CASE(ImplementorCid) {
const char* kScriptChars = R"(
abstract class AInterface {}
abstract class BInterface {}
class BImplementation implements BInterface {}
abstract class CInterface {}
class CImplementation1 implements CInterface {}
class CImplementation2 implements CInterface {}
abstract class DInterface {}
abstract class DSubinterface implements DInterface {}
abstract class EInterface {}
abstract class ESubinterface implements EInterface {}
class EImplementation implements ESubinterface {}
abstract class FInterface {}
abstract class FSubinterface implements FInterface {}
class FImplementation1 implements FSubinterface {}
class FImplementation2 implements FSubinterface {}
main() {
new BImplementation();
new CImplementation1();
new CImplementation2();
new EImplementation();
new FImplementation1();
new FImplementation2();
}
)";
Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(h_lib);
Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
EXPECT_VALID(result);
TransitionNativeToVM transition(thread);
const Library& lib =
Library::CheckedHandle(thread->zone(), Api::UnwrapHandle(h_lib));
EXPECT(!lib.IsNull());
const Class& AInterface = Class::Handle(GetClass(lib, "AInterface"));
EXPECT_EQ(AInterface.implementor_cid(), kIllegalCid);
const Class& BInterface = Class::Handle(GetClass(lib, "BInterface"));
const Class& BImplementation =
Class::Handle(GetClass(lib, "BImplementation"));
EXPECT_EQ(BInterface.implementor_cid(), BImplementation.id());
EXPECT_EQ(BImplementation.implementor_cid(), BImplementation.id());
const Class& CInterface = Class::Handle(GetClass(lib, "CInterface"));
const Class& CImplementation1 =
Class::Handle(GetClass(lib, "CImplementation1"));
const Class& CImplementation2 =
Class::Handle(GetClass(lib, "CImplementation2"));
EXPECT_EQ(CInterface.implementor_cid(), kDynamicCid);
EXPECT_EQ(CImplementation1.implementor_cid(), CImplementation1.id());
EXPECT_EQ(CImplementation2.implementor_cid(), CImplementation2.id());
const Class& DInterface = Class::Handle(GetClass(lib, "DInterface"));
const Class& DSubinterface = Class::Handle(GetClass(lib, "DSubinterface"));
EXPECT_EQ(DInterface.implementor_cid(), kIllegalCid);
EXPECT_EQ(DSubinterface.implementor_cid(), kIllegalCid);
const Class& EInterface = Class::Handle(GetClass(lib, "EInterface"));
const Class& ESubinterface = Class::Handle(GetClass(lib, "ESubinterface"));
const Class& EImplementation =
Class::Handle(GetClass(lib, "EImplementation"));
EXPECT_EQ(EInterface.implementor_cid(), EImplementation.id());
EXPECT_EQ(ESubinterface.implementor_cid(), EImplementation.id());
EXPECT_EQ(EImplementation.implementor_cid(), EImplementation.id());
const Class& FInterface = Class::Handle(GetClass(lib, "FInterface"));
const Class& FSubinterface = Class::Handle(GetClass(lib, "FSubinterface"));
const Class& FImplementation1 =
Class::Handle(GetClass(lib, "FImplementation1"));
const Class& FImplementation2 =
Class::Handle(GetClass(lib, "FImplementation2"));
EXPECT_EQ(FInterface.implementor_cid(), kDynamicCid);
EXPECT_EQ(FSubinterface.implementor_cid(), kDynamicCid);
EXPECT_EQ(FImplementation1.implementor_cid(), FImplementation1.id());
EXPECT_EQ(FImplementation2.implementor_cid(), FImplementation2.id());
}
ISOLATE_UNIT_TEST_CASE(MirrorReference) {
const MirrorReference& reference =
MirrorReference::Handle(MirrorReference::New(Object::Handle()));

View file

@ -1059,6 +1059,7 @@ class UntaggedClass : public UntaggedObject {
NOT_IN_PRECOMPILED(TokenPosition token_pos_);
NOT_IN_PRECOMPILED(TokenPosition end_token_pos_);
NOT_IN_PRECOMPILED(classid_t implementor_cid_);
classid_t id_; // Class Id, also index in the class table.
int16_t num_type_arguments_; // Number of type arguments in flattened vector.
@ -1099,6 +1100,7 @@ class UntaggedClass : public UntaggedObject {
friend class InstanceSerializationCluster;
friend class TypeSerializationCluster;
friend class CidRewriteVisitor;
friend class FinalizeVMIsolateVisitor;
friend class Api;
};