mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[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:
parent
955f1e90ec
commit
139d9216ad
|
@ -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>();
|
||||
|
||||
|
|
|
@ -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_);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue