@@ -47,6 +47,66 @@ DEFINE_FLAG(bool,
47
47
" Support unboxed double and float32x4 fields." );
48
48
DECLARE_FLAG (bool , eliminate_type_checks);
49
49
50
+ class SubclassFinder {
51
+ public:
52
+ SubclassFinder (Zone* zone,
53
+ GrowableArray<intptr_t >* cids,
54
+ bool include_abstract)
55
+ : array_handles_(zone),
56
+ class_handles_ (zone),
57
+ cids_(cids),
58
+ include_abstract_(include_abstract) {}
59
+
60
+ void ScanSubClasses (const Class& klass) {
61
+ if (include_abstract_ || !klass.is_abstract ()) {
62
+ cids_->Add (klass.id ());
63
+ }
64
+ ScopedHandle<GrowableObjectArray> array (&array_handles_);
65
+ ScopedHandle<Class> subclass (&class_handles_);
66
+ *array = klass.direct_subclasses ();
67
+ if (!array->IsNull ()) {
68
+ for (intptr_t i = 0 ; i < array->Length (); ++i) {
69
+ *subclass ^= array->At (i);
70
+ ScanSubClasses (*subclass);
71
+ }
72
+ }
73
+ }
74
+
75
+ void ScanImplementorClasses (const Class& klass) {
76
+ // An implementor of [klass] is
77
+ // * the [klass] itself.
78
+ // * all implementors of the direct subclasses of [klass].
79
+ // * all implementors of the direct implementors of [klass].
80
+ if (include_abstract_ || !klass.is_abstract ()) {
81
+ cids_->Add (klass.id ());
82
+ }
83
+
84
+ ScopedHandle<GrowableObjectArray> array (&array_handles_);
85
+ ScopedHandle<Class> subclass_or_implementor (&class_handles_);
86
+
87
+ *array = klass.direct_subclasses ();
88
+ if (!array->IsNull ()) {
89
+ for (intptr_t i = 0 ; i < array->Length (); ++i) {
90
+ *subclass_or_implementor ^= (*array).At (i);
91
+ ScanImplementorClasses (*subclass_or_implementor);
92
+ }
93
+ }
94
+ *array = klass.direct_implementors ();
95
+ if (!array->IsNull ()) {
96
+ for (intptr_t i = 0 ; i < array->Length (); ++i) {
97
+ *subclass_or_implementor ^= (*array).At (i);
98
+ ScanImplementorClasses (*subclass_or_implementor);
99
+ }
100
+ }
101
+ }
102
+
103
+ private:
104
+ ReusableHandleStack<GrowableObjectArray> array_handles_;
105
+ ReusableHandleStack<Class> class_handles_;
106
+ GrowableArray<intptr_t >* cids_;
107
+ const bool include_abstract_;
108
+ };
109
+
50
110
const CidRangeVector& HierarchyInfo::SubtypeRangesForClass (
51
111
const Class& klass,
52
112
bool include_abstract) {
@@ -60,8 +120,13 @@ const CidRangeVector& HierarchyInfo::SubtypeRangesForClass(
60
120
61
121
CidRangeVector& ranges = (*cid_ranges)[klass.id ()];
62
122
if (ranges.length () == 0 ) {
63
- BuildRangesFor (table, &ranges, klass, /* use_subtype_test=*/ true ,
64
- include_abstract);
123
+ if (!FLAG_precompiled_mode) {
124
+ BuildRangesForJIT (table, &ranges, klass, /* use_subtype_test=*/ true ,
125
+ include_abstract);
126
+ } else {
127
+ BuildRangesFor (table, &ranges, klass, /* use_subtype_test=*/ true ,
128
+ include_abstract);
129
+ }
65
130
}
66
131
return ranges;
67
132
}
@@ -76,7 +141,11 @@ const CidRangeVector& HierarchyInfo::SubclassRangesForClass(
76
141
77
142
CidRangeVector& ranges = cid_subclass_ranges_[klass.id ()];
78
143
if (ranges.length () == 0 ) {
79
- BuildRangesFor (table, &ranges, klass, /* use_subtype_test=*/ false );
144
+ if (!FLAG_precompiled_mode) {
145
+ BuildRangesForJIT (table, &ranges, klass, /* use_subtype_test=*/ true );
146
+ } else {
147
+ BuildRangesFor (table, &ranges, klass, /* use_subtype_test=*/ false );
148
+ }
80
149
}
81
150
return ranges;
82
151
}
@@ -87,12 +156,14 @@ void HierarchyInfo::BuildRangesFor(ClassTable* table,
87
156
bool use_subtype_test,
88
157
bool include_abstract) {
89
158
Zone* zone = thread ()->zone ();
90
- Class& cls = Class::Handle (zone );
159
+ ClassTable* class_table = thread ()-> isolate ()-> class_table ( );
91
160
92
161
// Only really used if `use_subtype_test == true`.
93
162
const Type& dst_type = Type::Handle (zone, Type::RawCast (klass.RareType ()));
94
163
AbstractType& cls_type = AbstractType::Handle (zone);
95
164
165
+ Class& cls = Class::Handle (zone);
166
+ AbstractType& super_type = AbstractType::Handle (zone);
96
167
const intptr_t cid_count = table->NumCids ();
97
168
98
169
intptr_t start = -1 ;
@@ -123,7 +194,10 @@ void HierarchyInfo::BuildRangesFor(ClassTable* table,
123
194
test_succeded = true ;
124
195
break ;
125
196
}
126
- cls = cls.SuperClass ();
197
+
198
+ super_type = cls.super_type ();
199
+ const intptr_t type_class_id = super_type.type_class_id ();
200
+ cls = class_table->At (type_class_id);
127
201
}
128
202
}
129
203
@@ -148,6 +222,94 @@ void HierarchyInfo::BuildRangesFor(ClassTable* table,
148
222
}
149
223
}
150
224
225
+ void HierarchyInfo::BuildRangesForJIT (ClassTable* table,
226
+ CidRangeVector* ranges,
227
+ const Class& dst_klass,
228
+ bool use_subtype_test,
229
+ bool include_abstract) {
230
+ if (dst_klass.InVMHeap ()) {
231
+ BuildRangesFor (table, ranges, dst_klass, use_subtype_test,
232
+ include_abstract);
233
+ return ;
234
+ }
235
+
236
+ Zone* zone = thread ()->zone ();
237
+ GrowableArray<intptr_t > cids;
238
+ SubclassFinder finder (zone, &cids, include_abstract);
239
+ if (use_subtype_test) {
240
+ finder.ScanImplementorClasses (dst_klass);
241
+ } else {
242
+ finder.ScanSubClasses (dst_klass);
243
+ }
244
+
245
+ // Sort all collected cids.
246
+ intptr_t * cids_array = cids.data ();
247
+
248
+ qsort (cids_array, cids.length (), sizeof (intptr_t ),
249
+ [](const void * a, const void * b) {
250
+ return static_cast <int >(*static_cast <const intptr_t *>(a) -
251
+ *static_cast <const intptr_t *>(b));
252
+ });
253
+
254
+ // Build ranges of all the cids.
255
+ Class& klass = Class::Handle ();
256
+ intptr_t left_cid = -1 ;
257
+ intptr_t last_cid = -1 ;
258
+ for (intptr_t i = 0 ; i < cids.length (); ++i) {
259
+ if (left_cid == -1 ) {
260
+ left_cid = last_cid = cids[i];
261
+ } else {
262
+ const intptr_t current_cid = cids[i];
263
+
264
+ // Skip duplicates.
265
+ if (current_cid == last_cid) continue ;
266
+
267
+ // Consecutive numbers cids are ok.
268
+ if (current_cid == (last_cid + 1 )) {
269
+ last_cid = current_cid;
270
+ } else {
271
+ // We sorted, after all!
272
+ RELEASE_ASSERT (last_cid < current_cid);
273
+
274
+ intptr_t j = last_cid + 1 ;
275
+ for (; j < current_cid; ++j) {
276
+ if (table->HasValidClassAt (j)) {
277
+ klass = table->At (j);
278
+ if (!klass.is_patch () && !klass.IsTopLevel ()) {
279
+ // If we care about abstract classes also, we cannot skip over any
280
+ // arbitrary abstract class, only those which are subtypes.
281
+ if (include_abstract) {
282
+ break ;
283
+ }
284
+
285
+ // If the class is concrete we cannot skip over it.
286
+ if (!klass.is_abstract ()) {
287
+ break ;
288
+ }
289
+ }
290
+ }
291
+ }
292
+
293
+ if (current_cid == j) {
294
+ // If there's only abstract cids between [last_cid] and the
295
+ // [current_cid] then we connect them.
296
+ last_cid = current_cid;
297
+ } else {
298
+ // Finish the current open cid range and start a new one.
299
+ ranges->Add (CidRange{left_cid, last_cid});
300
+ left_cid = last_cid = current_cid;
301
+ }
302
+ }
303
+ }
304
+ }
305
+
306
+ // If there is an open cid-range which we haven't finished yet, we'll
307
+ // complete it.
308
+ if (left_cid != -1 ) {
309
+ ranges->Add (CidRange{left_cid, last_cid});
310
+ }
311
+ }
312
+
151
313
bool HierarchyInfo::CanUseSubtypeRangeCheckFor (const AbstractType& type) {
152
314
ASSERT (type.IsFinalized () && !type.IsMalformedOrMalbounded ());
153
315
0 commit comments