@@ -1186,9 +1186,7 @@ bool Interpreter::AssertAssignable(Thread* thread,
1186
1186
ObjectPtr* args,
1187
1187
SubtypeTestCachePtr cache) {
1188
1188
ObjectPtr null_value = Object::null ();
1189
- if ((cache != null_value) &&
1190
- (Smi::Value (cache->untag ()->cache ()->untag ()->length ()) <=
1191
- SubtypeTestCache::kMaxLinearCacheSize )) {
1189
+ if (cache != null_value) {
1192
1190
InstancePtr instance = Instance::RawCast (args[0 ]);
1193
1191
AbstractTypePtr dst_type = AbstractType::RawCast (args[1 ]);
1194
1192
TypeArgumentsPtr instantiator_type_arguments =
@@ -1232,36 +1230,95 @@ bool Interpreter::AssertAssignable(Thread* thread,
1232
1230
}
1233
1231
1234
1232
ArrayPtr entries = cache->untag ()->cache ();
1235
- for (intptr_t i = 0 ; entries->untag ()->element (i) != null_value;
1236
- i += SubtypeTestCache::kTestEntryLength ) {
1237
- if ((entries->untag ()->element (
1238
- i + SubtypeTestCache::kInstanceCidOrSignature ) ==
1239
- instance_cid_or_function) &&
1240
- (entries->untag ()->element (
1241
- i + SubtypeTestCache::kInstanceTypeArguments ) ==
1242
- instance_type_arguments) &&
1243
- (entries->untag ()->element (
1244
- i + SubtypeTestCache::kInstantiatorTypeArguments ) ==
1245
- instantiator_type_arguments) &&
1246
- (entries->untag ()->element (
1247
- i + SubtypeTestCache::kFunctionTypeArguments ) ==
1248
- function_type_arguments) &&
1249
- (entries->untag ()->element (
1250
- i + SubtypeTestCache::kInstanceParentFunctionTypeArguments ) ==
1251
- parent_function_type_arguments) &&
1252
- (entries->untag ()->element (
1253
- i + SubtypeTestCache::kInstanceDelayedFunctionTypeArguments ) ==
1254
- delayed_function_type_arguments) &&
1255
- (entries->untag ()->element (i + SubtypeTestCache::kDestinationType ) ==
1256
- dst_type)) {
1257
- if (Bool::True ().ptr () ==
1258
- entries->untag ()->element (i + SubtypeTestCache::kTestResult )) {
1259
- return true ;
1260
- } else {
1261
- break ;
1233
+ const intptr_t num_inputs = cache->untag ()->num_inputs_ ;
1234
+ // The search in a linear-based STC starts at 0.
1235
+ intptr_t probe = 0 ;
1236
+ if (SubtypeTestCache::IsHash (entries)) {
1237
+ // Perform the same hash as SubtypeTestCache::FindKeyOrUnused.
1238
+ //
1239
+ // Control flows to AssertAssignableCallRuntime if any of the individual
1240
+ // hashes are 0 (which denotes the hash is not yet computed).
1241
+ if (cid == kClosureCid ) {
1242
+ auto sig = AbstractType::RawCast (instance_cid_or_function);
1243
+ probe = RawSmiValue (sig->untag ()->hash ());
1244
+ if (probe == 0 ) goto AssertAssignableCallRuntime;
1245
+ } else {
1246
+ probe = cid;
1247
+ }
1248
+ switch (num_inputs) {
1249
+ case 7 : {
1250
+ intptr_t h = RawSmiValue (dst_type->untag ()->hash ());
1251
+ if (h == 0 ) goto AssertAssignableCallRuntime;
1252
+ probe = CombineHashes (probe, h);
1262
1253
}
1254
+ FALL_THROUGH;
1255
+ case 6 : {
1256
+ intptr_t h = TypeArguments::kAllDynamicHash ;
1257
+ if (delayed_function_type_arguments != null_value) {
1258
+ h = RawSmiValue (delayed_function_type_arguments->untag ()->hash ());
1259
+ if (h == 0 ) goto AssertAssignableCallRuntime;
1260
+ }
1261
+ probe = CombineHashes (probe, h);
1262
+ }
1263
+ FALL_THROUGH;
1264
+ case 5 : {
1265
+ intptr_t h = TypeArguments::kAllDynamicHash ;
1266
+ if (parent_function_type_arguments != null_value) {
1267
+ h = RawSmiValue (parent_function_type_arguments->untag ()->hash ());
1268
+ if (h == 0 ) goto AssertAssignableCallRuntime;
1269
+ }
1270
+ probe = CombineHashes (probe, h);
1271
+ }
1272
+ FALL_THROUGH;
1273
+ case 4 : {
1274
+ intptr_t h = TypeArguments::kAllDynamicHash ;
1275
+ if (function_type_arguments != null_value) {
1276
+ h = RawSmiValue (function_type_arguments->untag ()->hash ());
1277
+ if (h == 0 ) goto AssertAssignableCallRuntime;
1278
+ }
1279
+ probe = CombineHashes (probe, h);
1280
+ }
1281
+ FALL_THROUGH;
1282
+ case 3 : {
1283
+ intptr_t h = TypeArguments::kAllDynamicHash ;
1284
+ if (instantiator_type_arguments != null_value) {
1285
+ h = RawSmiValue (instantiator_type_arguments->untag ()->hash ());
1286
+ if (h == 0 ) goto AssertAssignableCallRuntime;
1287
+ }
1288
+ probe = CombineHashes (probe, h);
1289
+ }
1290
+ FALL_THROUGH;
1291
+ case 2 : {
1292
+ intptr_t h = TypeArguments::kAllDynamicHash ;
1293
+ if (instance_type_arguments != null_value) {
1294
+ h = RawSmiValue (instance_type_arguments->untag ()->hash ());
1295
+ if (h == 0 ) goto AssertAssignableCallRuntime;
1296
+ }
1297
+ probe = CombineHashes (probe, h);
1298
+ }
1299
+ FALL_THROUGH;
1300
+ case 1 :
1301
+ // Already included in the hash.
1302
+ break ;
1303
+ default :
1304
+ UNREACHABLE ();
1263
1305
}
1306
+ probe = FinalizeHash (probe);
1307
+ // The number of entries for a hash-based cache is a power of 2,
1308
+ // so use it as a mask to get a valid entry index from the hash.
1309
+ probe = probe & (SubtypeTestCache::NumEntries (entries) - 1 );
1310
+ }
1311
+ BoolPtr test_result = nullptr ;
1312
+ auto loc = SubtypeTestCache::FindKeyOrUnusedFromProbe (
1313
+ entries, num_inputs, probe, instance_cid_or_function, dst_type,
1314
+ instance_type_arguments, instantiator_type_arguments,
1315
+ function_type_arguments, parent_function_type_arguments,
1316
+ delayed_function_type_arguments, &test_result);
1317
+ if (loc.present && test_result == Bool::True ().ptr ()) {
1318
+ return true ;
1264
1319
}
1320
+ // Either there is no matching entry or the matching entry had a false test
1321
+ // result, so a runtime call is needed to generate an appropriate error.
1265
1322
}
1266
1323
1267
1324
AssertAssignableCallRuntime:
0 commit comments