|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | 3 |
|
4 | 4 | using System.Diagnostics; |
5 | | -using Internal.Runtime.CompilerServices; |
6 | 5 | using System.Runtime.InteropServices; |
7 | 6 | using System.Threading; |
8 | | -using System.Runtime.Intrinsics; |
9 | | -using System.Runtime.Intrinsics.X86; |
| 7 | + |
| 8 | +using Internal.Runtime.CompilerServices; |
10 | 9 |
|
11 | 10 | namespace System.Runtime.CompilerServices |
12 | 11 | { |
@@ -207,34 +206,57 @@ private static CastResult TryGet(nuint source, nuint target) |
207 | 206 | [DebuggerStepThrough] |
208 | 207 | private static object? IsInstanceOfInterface(void* toTypeHnd, object? obj) |
209 | 208 | { |
| 209 | + const int unrollSize = 4; |
| 210 | + |
210 | 211 | if (obj != null) |
211 | 212 | { |
212 | 213 | MethodTable* mt = RuntimeHelpers.GetMethodTable(obj); |
213 | | - nuint interfaceCount = mt->InterfaceCount; |
| 214 | + nint interfaceCount = mt->InterfaceCount; |
214 | 215 | if (interfaceCount != 0) |
215 | 216 | { |
216 | 217 | MethodTable** interfaceMap = mt->InterfaceMap; |
217 | | - for (nuint i = 0; ; i += 4) |
| 218 | + if (interfaceCount < unrollSize) |
218 | 219 | { |
219 | | - if (interfaceMap[i + 0] == toTypeHnd) |
220 | | - goto done; |
221 | | - if (--interfaceCount == 0) |
222 | | - break; |
223 | | - if (interfaceMap[i + 1] == toTypeHnd) |
224 | | - goto done; |
225 | | - if (--interfaceCount == 0) |
226 | | - break; |
227 | | - if (interfaceMap[i + 2] == toTypeHnd) |
228 | | - goto done; |
229 | | - if (--interfaceCount == 0) |
230 | | - break; |
231 | | - if (interfaceMap[i + 3] == toTypeHnd) |
| 220 | + // If not enough for unrolled, jmp straight to small loop |
| 221 | + // as we already know there is one or more interfaces so don't need to check again. |
| 222 | + goto few; |
| 223 | + } |
| 224 | + |
| 225 | + do |
| 226 | + { |
| 227 | + if (interfaceMap[0] == toTypeHnd || |
| 228 | + interfaceMap[1] == toTypeHnd || |
| 229 | + interfaceMap[2] == toTypeHnd || |
| 230 | + interfaceMap[3] == toTypeHnd) |
| 231 | + { |
232 | 232 | goto done; |
233 | | - if (--interfaceCount == 0) |
234 | | - break; |
| 233 | + } |
| 234 | + |
| 235 | + interfaceMap += unrollSize; |
| 236 | + interfaceCount -= unrollSize; |
| 237 | + } while (interfaceCount >= unrollSize); |
| 238 | + |
| 239 | + if (interfaceCount == 0) |
| 240 | + { |
| 241 | + // If none remaining, skip the short loop |
| 242 | + goto extra; |
235 | 243 | } |
| 244 | + |
| 245 | + few: |
| 246 | + do |
| 247 | + { |
| 248 | + if (interfaceMap[0] == toTypeHnd) |
| 249 | + { |
| 250 | + goto done; |
| 251 | + } |
| 252 | + |
| 253 | + // Assign next offset |
| 254 | + interfaceMap++; |
| 255 | + interfaceCount--; |
| 256 | + } while (interfaceCount > 0); |
236 | 257 | } |
237 | 258 |
|
| 259 | + extra: |
238 | 260 | if (mt->NonTrivialInterfaceCast) |
239 | 261 | { |
240 | 262 | goto slowPath; |
@@ -374,35 +396,60 @@ private static CastResult TryGet(nuint source, nuint target) |
374 | 396 | [DebuggerStepThrough] |
375 | 397 | private static object? ChkCastInterface(void* toTypeHnd, object? obj) |
376 | 398 | { |
| 399 | + const int unrollSize = 4; |
| 400 | + |
377 | 401 | if (obj != null) |
378 | 402 | { |
379 | 403 | MethodTable* mt = RuntimeHelpers.GetMethodTable(obj); |
380 | | - nuint interfaceCount = mt->InterfaceCount; |
| 404 | + nint interfaceCount = mt->InterfaceCount; |
381 | 405 | if (interfaceCount == 0) |
382 | 406 | { |
383 | 407 | goto slowPath; |
384 | 408 | } |
385 | 409 |
|
386 | 410 | MethodTable** interfaceMap = mt->InterfaceMap; |
387 | | - for (nuint i = 0; ; i += 4) |
| 411 | + if (interfaceCount < unrollSize) |
388 | 412 | { |
389 | | - if (interfaceMap[i + 0] == toTypeHnd) |
390 | | - goto done; |
391 | | - if (--interfaceCount == 0) |
392 | | - goto slowPath; |
393 | | - if (interfaceMap[i + 1] == toTypeHnd) |
394 | | - goto done; |
395 | | - if (--interfaceCount == 0) |
396 | | - goto slowPath; |
397 | | - if (interfaceMap[i + 2] == toTypeHnd) |
398 | | - goto done; |
399 | | - if (--interfaceCount == 0) |
400 | | - goto slowPath; |
401 | | - if (interfaceMap[i + 3] == toTypeHnd) |
| 413 | + // If not enough for unrolled, jmp straight to small loop |
| 414 | + // as we already know there is one or more interfaces so don't need to check again. |
| 415 | + goto few; |
| 416 | + } |
| 417 | + |
| 418 | + do |
| 419 | + { |
| 420 | + if (interfaceMap[0] == toTypeHnd || |
| 421 | + interfaceMap[1] == toTypeHnd || |
| 422 | + interfaceMap[2] == toTypeHnd || |
| 423 | + interfaceMap[3] == toTypeHnd) |
| 424 | + { |
402 | 425 | goto done; |
403 | | - if (--interfaceCount == 0) |
404 | | - goto slowPath; |
| 426 | + } |
| 427 | + |
| 428 | + // Assign next offset |
| 429 | + interfaceMap += unrollSize; |
| 430 | + interfaceCount -= unrollSize; |
| 431 | + } while (interfaceCount >= unrollSize); |
| 432 | + |
| 433 | + if (interfaceCount == 0) |
| 434 | + { |
| 435 | + // If none remaining, skip the short loop |
| 436 | + goto slowPath; |
405 | 437 | } |
| 438 | + |
| 439 | + few: |
| 440 | + do |
| 441 | + { |
| 442 | + if (interfaceMap[0] == toTypeHnd) |
| 443 | + { |
| 444 | + goto done; |
| 445 | + } |
| 446 | + |
| 447 | + // Assign next offset |
| 448 | + interfaceMap++; |
| 449 | + interfaceCount--; |
| 450 | + } while (interfaceCount > 0); |
| 451 | + |
| 452 | + goto slowPath; |
406 | 453 | } |
407 | 454 |
|
408 | 455 | done: |
|
0 commit comments