Flutter Engine
The Flutter Engine
cha.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/compiler/cha.h"
6#include "vm/class_table.h"
8#include "vm/flags.h"
9#include "vm/log.h"
10#include "vm/object.h"
11#include "vm/raw_object.h"
12#include "vm/visitor.h"
13
14namespace dart {
15
16void CHA::AddToGuardedClasses(const Class& cls,
17 intptr_t subclass_count,
18 intptr_t implementor_cid,
19 bool track_future) {
20 for (intptr_t i = 0; i < guarded_classes_.length(); i++) {
21 if (guarded_classes_[i].cls->ptr() == cls.ptr()) {
22 if ((subclass_count >= 0) && (guarded_classes_[i].subclass_count == -1)) {
23 guarded_classes_[i].subclass_count = subclass_count;
24 }
25 if ((implementor_cid != kIllegalCid) &&
26 (guarded_classes_[i].implementor_cid == kIllegalCid)) {
27 guarded_classes_[i].implementor_cid = implementor_cid;
28 }
29 if (track_future && !guarded_classes_[i].track_future) {
30 guarded_classes_[i].track_future = track_future;
31 }
32 return;
33 }
34 }
35 GuardedClassInfo info = {&Class::ZoneHandle(thread_->zone(), cls.ptr()),
36 subclass_count, implementor_cid, track_future};
37 guarded_classes_.Add(info);
38}
39
41 intptr_t subclass_count) {
42 ASSERT(subclass_count >= 0);
43 AddToGuardedClasses(cls, subclass_count, kIllegalCid, false);
44}
45
47 intptr_t implementor_cid) {
48 ASSERT(implementor_cid != kIllegalCid);
49 ASSERT(implementor_cid != kDynamicCid);
50 AddToGuardedClasses(cls, -1, implementor_cid, false);
51}
52
54 AddToGuardedClasses(cls, -1, kIllegalCid, true);
55}
56
57bool CHA::IsGuardedClass(intptr_t cid) const {
58 for (intptr_t i = 0; i < guarded_classes_.length(); ++i) {
59 if (guarded_classes_[i].cls->id() == cid) return true;
60 }
61 return false;
62}
63
64bool CHA::HasSubclasses(const Class& cls) {
65 ASSERT(!cls.IsNull());
67 // Can't track dependencies for classes on the VM heap since those are
68 // read-only.
69 // TODO(fschneider): Enable tracking of CHA dependent code for VM heap
70 // classes.
71 if (cls.InVMIsolateHeap()) return true;
72
73 if (cls.IsObjectClass()) {
74 // Class Object has subclasses, although we do not keep track of them.
75 return true;
76 }
77
78 if (cls.has_dynamically_extendable_subtypes()) return true;
79
80 Thread* thread = Thread::Current();
81 SafepointReadRwLocker ml(thread, thread->isolate_group()->program_lock());
82 const GrowableObjectArray& direct_subclasses =
84 return !direct_subclasses.IsNull() && (direct_subclasses.Length() > 0);
85}
86
87bool CHA::HasSubclasses(intptr_t cid) const {
88 const ClassTable& class_table = *thread_->isolate_group()->class_table();
89 Class& cls = Class::Handle(thread_->zone(), class_table.At(cid));
90 return HasSubclasses(cls);
91}
92
94 GrowableArray<intptr_t>* class_ids) {
95 if (cls.InVMIsolateHeap()) return false;
96 if (cls.IsObjectClass()) return false;
97 if (cls.has_dynamically_extendable_subtypes()) return false;
98
99 if (!cls.is_abstract()) {
100 class_ids->Add(cls.id());
101 }
102
103 // This is invoked from precompiler only, we can use unsafe version of
104 // Class::direct_subclasses getter.
105 ASSERT(FLAG_precompiled_mode);
106 const GrowableObjectArray& direct_subclasses =
108 if (direct_subclasses.IsNull()) {
109 return true;
110 }
111 Class& subclass = Class::Handle();
112 for (intptr_t i = 0; i < direct_subclasses.Length(); i++) {
113 subclass ^= direct_subclasses.At(i);
114 if (!ConcreteSubclasses(subclass, class_ids)) {
115 return false;
116 }
117 }
118 return true;
119}
120
121bool CHA::IsImplemented(const Class& cls) {
122 // Can't track dependencies for classes on the VM heap since those are
123 // read-only.
124 // TODO(fschneider): Enable tracking of CHA dependent code for VM heap
125 // classes.
126 if (cls.InVMIsolateHeap()) return true;
127 if (cls.has_dynamically_extendable_subtypes()) return true;
128
129 return cls.is_implemented();
130}
131
133 intptr_t* implementation_cid) {
134 intptr_t cid = interface.implementor_cid();
135 if ((cid == kIllegalCid) || (cid == kDynamicCid) ||
137 // No implementations / multiple implementations.
138 *implementation_cid = kDynamicCid;
139 return false;
140 }
141
142 Thread* thread = Thread::Current();
143 if (FLAG_use_cha_deopt || thread->isolate_group()->all_classes_finalized()) {
144 if (FLAG_trace_cha) {
145 THR_Print(" **(CHA) Type has one implementation: %s\n",
146 interface.ToCString());
147 }
148 if (FLAG_use_cha_deopt) {
149 CHA& cha = thread->compiler_state().cha();
151 }
152 *implementation_cid = cid;
153 return true;
154 } else {
155 *implementation_cid = kDynamicCid;
156 return false;
157 }
158}
159
160bool CHA::ClassCanBeFuture(const Class& cls) {
161 if (cls.can_be_future()) {
162 return true;
163 }
164
165 // Class cannot be Future with the current set of
166 // finalized classes. However, as new classes are loaded
167 // and finalized, there could be a new subtype of [cls]
168 // which is also a subtype of Future.
169 // We should deoptimize in such cases.
170 Thread* thread = Thread::Current();
171 if (FLAG_use_cha_deopt || thread->isolate_group()->all_classes_finalized()) {
172 if (FLAG_use_cha_deopt) {
173 CHA& cha = thread->compiler_state().cha();
175 }
176 return false;
177 }
178
179 // Conservatively assume that class can be Future.
180 return true;
181}
182
183static intptr_t CountFinalizedSubclasses(Thread* thread, const Class& cls) {
184 intptr_t count = 0;
185 const GrowableObjectArray& cls_direct_subclasses =
187 if (cls_direct_subclasses.IsNull()) return count;
188 Class& direct_subclass = Class::Handle(thread->zone());
189 for (intptr_t i = 0; i < cls_direct_subclasses.Length(); i++) {
190 direct_subclass ^= cls_direct_subclasses.At(i);
191 // Unfinalized classes are treated as nonexistent for CHA purposes,
192 // as that means that no instance of that class exists at runtime.
193 if (!direct_subclass.is_finalized()) {
194 continue;
195 }
196
197 count += 1 + CountFinalizedSubclasses(thread, direct_subclass);
198 }
199 return count;
200}
201
203 for (intptr_t i = 0; i < guarded_classes_.length(); i++) {
204 if (guarded_classes_[i].subclass_count != -1) {
205 intptr_t current_subclass_count =
206 CountFinalizedSubclasses(thread_, *guarded_classes_[i].cls);
207 if (guarded_classes_[i].subclass_count != current_subclass_count) {
208 return false; // New subclass appeared during compilation.
209 }
210 }
211 if (guarded_classes_[i].implementor_cid != kIllegalCid) {
212 intptr_t current_implementor_cid =
213 guarded_classes_[i].cls->implementor_cid();
214 if (guarded_classes_[i].implementor_cid != current_implementor_cid) {
215 return false; // New implementor appeared during compilation.
216 }
217 }
218 if (guarded_classes_[i].track_future) {
219 if (guarded_classes_[i].cls->can_be_future()) {
220 return false;
221 }
222 }
223 }
224 return true;
225}
226
227bool CHA::HasOverride(const Class& cls,
228 const String& function_name,
229 intptr_t* subclasses_count) {
230 // Can't track dependencies for classes on the VM heap since those are
231 // read-only.
232 // TODO(fschneider): Enable tracking of CHA dependent code for VM heap
233 // classes.
234 if (cls.InVMIsolateHeap()) return true;
235
236 // Subclasses of Object are not tracked by CHA. Safely assume that overrides
237 // exist.
238 if (cls.IsObjectClass()) {
239 return true;
240 }
241
242 SafepointReadRwLocker ml(thread_, thread_->isolate_group()->program_lock());
243 const GrowableObjectArray& cls_direct_subclasses =
245 if (cls_direct_subclasses.IsNull()) {
246 return false;
247 }
248 Class& direct_subclass = Class::Handle(thread_->zone());
249 for (intptr_t i = 0; i < cls_direct_subclasses.Length(); i++) {
250 direct_subclass ^= cls_direct_subclasses.At(i);
251 // Unfinalized classes are treated as nonexistent for CHA purposes,
252 // as that means that no instance of that class exists at runtime.
253 if (!direct_subclass.is_finalized()) {
254 continue;
255 }
256
257 if (direct_subclass.LookupDynamicFunctionUnsafe(function_name) !=
258 Function::null()) {
259 return true;
260 }
261
262 if (HasOverride(direct_subclass, function_name, subclasses_count)) {
263 return true;
264 }
265
266 (*subclasses_count)++;
267 }
268
269 return false;
270}
271
273 for (intptr_t i = 0; i < guarded_classes_.length(); ++i) {
274 guarded_classes_[i].cls->RegisterCHACode(code);
275 }
276}
277
278} // namespace dart
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
int count
Definition: FontMgrTest.cpp:50
void Add(const T &value)
intptr_t length() const
Definition: cha.h:25
bool HasOverride(const Class &cls, const String &function_name, intptr_t *subclass_count)
Definition: cha.cc:227
void AddToGuardedClassesForImplementorCid(const Class &cls, intptr_t implementor_cid)
Definition: cha.cc:46
void RegisterDependencies(const Code &code) const
Definition: cha.cc:272
static bool IsImplemented(const Class &cls)
Definition: cha.cc:121
bool IsGuardedClass(intptr_t cid) const
Definition: cha.cc:57
static bool HasSubclasses(const Class &cls)
Definition: cha.cc:64
void AddToGuardedClassesForSubclassCount(const Class &cls, intptr_t subclass_count)
Definition: cha.cc:40
static bool ConcreteSubclasses(const Class &cls, GrowableArray< intptr_t > *class_ids)
Definition: cha.cc:93
void AddToGuardedClassesToTrackFuture(const Class &cls)
Definition: cha.cc:53
static bool ClassCanBeFuture(const Class &cls)
Definition: cha.cc:160
bool IsConsistentWithCurrentHierarchy() const
Definition: cha.cc:202
static bool HasSingleConcreteImplementation(const Class &interface, intptr_t *implementation_cid)
Definition: cha.cc:132
ClassPtr At(intptr_t cid) const
Definition: class_table.h:362
bool has_dynamically_extendable_subtypes() const
Definition: object.h:2196
bool can_be_future() const
Definition: object.h:2188
GrowableObjectArrayPtr direct_subclasses() const
Definition: object.h:1537
intptr_t id() const
Definition: object.h:1233
bool IsObjectClass() const
Definition: object.h:1565
intptr_t implementor_cid() const
Definition: object.h:1245
FunctionPtr LookupDynamicFunctionUnsafe(const String &name) const
Definition: object.cc:6129
bool is_abstract() const
Definition: object.h:1696
GrowableObjectArrayPtr direct_subclasses_unsafe() const
Definition: object.h:1542
bool is_implemented() const
Definition: object.h:1692
bool is_finalized() const
Definition: object.h:1723
intptr_t Length() const
Definition: object.h:11072
ObjectPtr At(intptr_t index) const
Definition: object.h:11085
bool all_classes_finalized() const
Definition: isolate.h:713
SafepointRwLock * program_lock()
Definition: isolate.h:537
ClassTable * class_table() const
Definition: isolate.h:496
static ObjectPtr null()
Definition: object.h:433
bool InVMIsolateHeap() const
Definition: object.h:395
virtual const char * ToCString() const
Definition: object.h:366
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static Object & ZoneHandle()
Definition: object.h:419
Zone * zone() const
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
CompilerState & compiler_state()
Definition: thread.h:588
IsolateGroup * isolate_group() const
Definition: thread.h:541
#define THR_Print(format,...)
Definition: log.h:20
#define ASSERT(E)
Definition: dart_vm.cc:33
@ kIllegalCid
Definition: class_id.h:214
@ kDynamicCid
Definition: class_id.h:253
static intptr_t CountFinalizedSubclasses(Thread *thread, const Class &cls)
Definition: cha.cc:183
const intptr_t cid
bool IsInternalOnlyClassId(intptr_t index)
Definition: class_id.h:299
const char *const function_name