@@ -435,15 +435,17 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
435
435
stackPointer --;
436
436
int index = popInt (frame , stackPointer );
437
437
final int size = rawPeekU8 (bytecode , offset );
438
- if (index < 0 || index >= size ) {
439
- // If unsigned index is larger or equal to the table size use the
440
- // default (last) index.
441
- index = size - 1 ;
442
- }
438
+ final int counterOffset = offset + 1 ;
443
439
444
440
if (CompilerDirectives .inInterpreter ()) {
441
+ if (index < 0 || index >= size ) {
442
+ // If unsigned index is larger or equal to the table size use the
443
+ // default (last) index.
444
+ index = size - 1 ;
445
+ }
446
+
445
447
final int indexOffset = offset + 3 + index * 6 ;
446
- updateBranchTableProfile (bytecode , offset + 1 , indexOffset + 4 );
448
+ updateBranchTableProfile (bytecode , counterOffset , indexOffset + 4 );
447
449
final int offsetDelta = rawPeekI32 (bytecode , indexOffset );
448
450
offset = indexOffset + offsetDelta ;
449
451
break ;
@@ -453,29 +455,30 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
453
455
// time constants, since the loop is unrolled.
454
456
for (int i = 0 ; i < size ; i ++) {
455
457
final int indexOffset = offset + 3 + i * 6 ;
456
- if (profileBranchTable (bytecode , offset + 1 , indexOffset + 4 , i == index )) {
458
+ if (profileBranchTable (bytecode , counterOffset , indexOffset + 4 , i == index || i == size - 1 )) {
457
459
final int offsetDelta = rawPeekI32 (bytecode , indexOffset );
458
460
offset = indexOffset + offsetDelta ;
459
461
continue loop ;
460
462
}
461
463
}
464
+ throw CompilerDirectives .shouldNotReachHere ("br_table" );
462
465
}
463
- enterErrorBranch ();
464
- throw WasmException .create (Failure .UNSPECIFIED_INTERNAL , this , "Should not reach here" );
465
466
}
466
467
case Bytecode .BR_TABLE_I32 : {
467
468
stackPointer --;
468
469
int index = popInt (frame , stackPointer );
469
470
final int size = rawPeekI32 (bytecode , offset );
470
- if (index < 0 || index >= size ) {
471
- // If unsigned index is larger or equal to the table size use the
472
- // default (last) index.
473
- index = size - 1 ;
474
- }
471
+ final int counterOffset = offset + 4 ;
475
472
476
473
if (CompilerDirectives .inInterpreter ()) {
474
+ if (index < 0 || index >= size ) {
475
+ // If unsigned index is larger or equal to the table size use the
476
+ // default (last) index.
477
+ index = size - 1 ;
478
+ }
479
+
477
480
final int indexOffset = offset + 6 + index * 6 ;
478
- updateBranchTableProfile (bytecode , offset + 4 , indexOffset + 4 );
481
+ updateBranchTableProfile (bytecode , counterOffset , indexOffset + 4 );
479
482
final int offsetDelta = rawPeekI32 (bytecode , indexOffset );
480
483
offset = indexOffset + offsetDelta ;
481
484
break ;
@@ -485,15 +488,14 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
485
488
// time constants, since the loop is unrolled.
486
489
for (int i = 0 ; i < size ; i ++) {
487
490
final int indexOffset = offset + 6 + i * 6 ;
488
- if (profileBranchTable (bytecode , offset + 1 , indexOffset + 4 , i == index )) {
491
+ if (profileBranchTable (bytecode , counterOffset , indexOffset + 4 , i == index || i == size - 1 )) {
489
492
final int offsetDelta = rawPeekI32 (bytecode , indexOffset );
490
493
offset = indexOffset + offsetDelta ;
491
494
continue loop ;
492
495
}
493
496
}
497
+ throw CompilerDirectives .shouldNotReachHere ("br_table" );
494
498
}
495
- enterErrorBranch ();
496
- throw WasmException .create (Failure .UNSPECIFIED_INTERNAL , this , "Should not reach here" );
497
499
}
498
500
case Bytecode .CALL_U8 :
499
501
case Bytecode .CALL_I32 : {
@@ -4679,11 +4681,26 @@ private static boolean profileCondition(byte[] data, final int profileOffset, bo
4679
4681
}
4680
4682
4681
4683
private static void updateBranchTableProfile (byte [] data , final int counterOffset , final int profileOffset ) {
4682
- assert CompilerDirectives . inInterpreter ();
4684
+ CompilerAsserts . neverPartOfCompilation ();
4683
4685
int counter = rawPeekU16 (data , counterOffset );
4686
+ int profile = rawPeekU16 (data , profileOffset );
4687
+ /*
4688
+ * Even if the total hit counter has already reached the limit, we need to increment the
4689
+ * branch profile counter from 0 to 1 iff it's still 0 to mark the branch as having been
4690
+ * taken at least once, to prevent recurrent deoptimizations due to profileBranchTable
4691
+ * assuming that a value of 0 means the branch has never been reached.
4692
+ *
4693
+ * Similarly, we need to make sure we never increase any branch counter to the max value,
4694
+ * otherwise we can get into a situation where both the branch and the total counter values
4695
+ * are at the max value that we cannot recover from since we never decrease counter values;
4696
+ * profileBranchTable would then deoptimize every time that branch is not taken (see below).
4697
+ */
4698
+ assert profile != MAX_TABLE_PROFILE_VALUE ;
4684
4699
if (counter < MAX_TABLE_PROFILE_VALUE ) {
4685
4700
BinaryStreamParser .writeU16 (data , counterOffset , counter + 1 );
4686
- BinaryStreamParser .writeU16 (data , profileOffset , rawPeekU16 (data , profileOffset ) + 1 );
4701
+ }
4702
+ if ((counter < MAX_TABLE_PROFILE_VALUE || profile == 0 ) && (profile < MAX_TABLE_PROFILE_VALUE - 1 )) {
4703
+ BinaryStreamParser .writeU16 (data , profileOffset , profile + 1 );
4687
4704
}
4688
4705
}
4689
4706
0 commit comments