@@ -1186,9 +1186,7 @@ bool Interpreter::AssertAssignable(Thread* thread,
11861186 ObjectPtr* args,
11871187 SubtypeTestCachePtr cache) {
11881188 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) {
11921190 InstancePtr instance = Instance::RawCast (args[0 ]);
11931191 AbstractTypePtr dst_type = AbstractType::RawCast (args[1 ]);
11941192 TypeArgumentsPtr instantiator_type_arguments =
@@ -1232,36 +1230,95 @@ bool Interpreter::AssertAssignable(Thread* thread,
12321230 }
12331231
12341232 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);
12621253 }
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 ();
12631305 }
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 ;
12641319 }
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.
12651322 }
12661323
12671324AssertAssignableCallRuntime:
0 commit comments