@@ -894,7 +894,8 @@ enum ControlKind : uint8_t {
894
894
kControlLoop ,
895
895
kControlLet ,
896
896
kControlTry ,
897
- kControlTryCatch
897
+ kControlTryCatch ,
898
+ kControlTryCatchAll
898
899
};
899
900
900
901
enum Reachability : uint8_t {
@@ -953,7 +954,10 @@ struct ControlBase : public PcForErrors<validate> {
953
954
bool is_loop () const { return kind == kControlLoop ; }
954
955
bool is_incomplete_try () const { return kind == kControlTry ; }
955
956
bool is_try_catch () const { return kind == kControlTryCatch ; }
956
- bool is_try () const { return is_incomplete_try () || is_try_catch (); }
957
+ bool is_try_catchall () const { return kind == kControlTryCatchAll ; }
958
+ bool is_try () const {
959
+ return is_incomplete_try () || is_try_catch () || is_try_catchall ();
960
+ }
957
961
958
962
inline Merge<Value>* br_merge () {
959
963
return is_loop () ? &this ->start_merge : &this ->end_merge ;
@@ -974,7 +978,6 @@ struct ControlBase : public PcForErrors<validate> {
974
978
F (Block, Control* block) \
975
979
F (Loop, Control* block) \
976
980
F (Try, Control* block) \
977
- F (Catch, Control* block, Value* exception) \
978
981
F (If, const Value& cond, Control* if_block) \
979
982
F (FallThruTo, Control* c) \
980
983
F (PopControl, Control* block) \
@@ -1049,10 +1052,10 @@ struct ControlBase : public PcForErrors<validate> {
1049
1052
const Value& input0, const Value& input1, Value* result) \
1050
1053
F (Throw, const ExceptionIndexImmediate<validate>& imm, \
1051
1054
const Vector<Value>& args) \
1052
- F (Rethrow, const Value& exception) \
1053
- F (BrOnException , const Value& exception, \
1054
- const ExceptionIndexImmediate<validate>& imm, uint32_t depth, \
1055
- Vector<Value> values) \
1055
+ F (Rethrow, Control* block) \
1056
+ F (CatchException , const ExceptionIndexImmediate<validate>& imm, \
1057
+ Control* block, Vector<Value> caught_values) \
1058
+ F (CatchAll, Control* block) \
1056
1059
F (AtomicOp, WasmOpcode opcode, Vector<Value> args, \
1057
1060
const MemoryAccessImmediate<validate>& imm, Value* result) \
1058
1061
F (AtomicFence) \
@@ -1631,6 +1634,7 @@ class WasmDecoder : public Decoder {
1631
1634
nullptr );
1632
1635
return 1 + imm.length ;
1633
1636
}
1637
+ case kExprRethrow :
1634
1638
case kExprBr :
1635
1639
case kExprBrIf :
1636
1640
case kExprBrOnNull : {
@@ -1642,17 +1646,11 @@ class WasmDecoder : public Decoder {
1642
1646
BranchTableIterator<validate> iterator (decoder, imm);
1643
1647
return 1 + iterator.length ();
1644
1648
}
1645
- case kExprThrow : {
1649
+ case kExprThrow :
1650
+ case kExprCatch : {
1646
1651
ExceptionIndexImmediate<validate> imm (decoder, pc + 1 );
1647
1652
return 1 + imm.length ;
1648
1653
}
1649
- case kExprCatch :
1650
- case kExprRethrow :
1651
- return 1 ;
1652
- case kExprBrOnExn : {
1653
- BranchOnExceptionImmediate<validate> imm (decoder, pc + 1 );
1654
- return 1 + imm.length ;
1655
- }
1656
1654
case kExprLet : {
1657
1655
BlockTypeImmediate<validate> imm (WasmFeatures::All (), decoder, pc + 1 ,
1658
1656
nullptr );
@@ -1678,12 +1676,14 @@ class WasmDecoder : public Decoder {
1678
1676
case kExprReturnCallRef :
1679
1677
case kExprDrop :
1680
1678
case kExprSelect :
1679
+ case kExprCatchAll :
1681
1680
return 1 ;
1682
1681
case kExprSelectWithType : {
1683
1682
SelectTypeImmediate<validate> imm (WasmFeatures::All (), decoder, pc + 1 ,
1684
1683
nullptr );
1685
1684
return 1 + imm.length ;
1686
1685
}
1686
+
1687
1687
case kExprLocalGet :
1688
1688
case kExprLocalSet :
1689
1689
case kExprLocalTee : {
@@ -2016,7 +2016,6 @@ class WasmDecoder : public Decoder {
2016
2016
case kExprElse :
2017
2017
case kExprTry :
2018
2018
case kExprCatch :
2019
- case kExprBrOnExn :
2020
2019
case kExprNop :
2021
2020
case kExprReturn :
2022
2021
case kExprReturnCall :
@@ -2344,6 +2343,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
2344
2343
break ;
2345
2344
case kControlIfElse :
2346
2345
case kControlTryCatch :
2346
+ case kControlTryCatchAll :
2347
2347
case kControlLet : // TODO(7748): Implement
2348
2348
break ;
2349
2349
}
@@ -2404,10 +2404,16 @@ class WasmFullDecoder : public WasmDecoder<validate> {
2404
2404
2405
2405
DECODE (Rethrow) {
2406
2406
CHECK_PROTOTYPE_OPCODE (eh);
2407
- Value exception = Pop (0 , kWasmExnRef );
2408
- CALL_INTERFACE_IF_REACHABLE (Rethrow, exception);
2407
+ BranchDepthImmediate<validate> imm (this , this ->pc_ + 1 );
2408
+ if (!this ->Validate (this ->pc_ + 1 , imm, control_.size ())) return 0 ;
2409
+ Control* c = control_at (imm.depth );
2410
+ if (!VALIDATE (c->is_try_catchall () || c->is_try_catch ())) {
2411
+ this ->error (" rethrow not targeting catch or catch-all" );
2412
+ return 0 ;
2413
+ }
2414
+ CALL_INTERFACE_IF_REACHABLE (Rethrow, c);
2409
2415
EndControl ();
2410
- return 1 ;
2416
+ return 1 + imm. length ;
2411
2417
}
2412
2418
2413
2419
DECODE (Throw) {
@@ -2435,6 +2441,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
2435
2441
2436
2442
DECODE (Catch) {
2437
2443
CHECK_PROTOTYPE_OPCODE (eh);
2444
+ ExceptionIndexImmediate<validate> imm (this , this ->pc_ + 1 );
2445
+ if (!this ->Validate (this ->pc_ + 1 , imm)) return 0 ;
2438
2446
if (!VALIDATE (!control_.empty ())) {
2439
2447
this ->DecodeError (" catch does not match any try" );
2440
2448
return 0 ;
@@ -2444,46 +2452,46 @@ class WasmFullDecoder : public WasmDecoder<validate> {
2444
2452
this ->DecodeError (" catch does not match any try" );
2445
2453
return 0 ;
2446
2454
}
2447
- if (!VALIDATE (c->is_incomplete_try ())) {
2448
- this ->DecodeError (" catch already present for try" );
2455
+ if (!VALIDATE (! c->is_try_catchall ())) {
2456
+ this ->DecodeError (" catch after catch-all for try" );
2449
2457
return 0 ;
2450
2458
}
2451
2459
c->kind = kControlTryCatch ;
2452
2460
FallThruTo (c);
2453
2461
DCHECK_LE (stack_ + c->stack_depth , stack_end_);
2454
2462
stack_end_ = stack_ + c->stack_depth ;
2455
2463
c->reachability = control_at (1 )->innerReachability ();
2464
+ const WasmExceptionSig* sig = imm.exception ->sig ;
2465
+ for (size_t i = 0 , e = sig->parameter_count (); i < e; ++i) {
2466
+ Push (sig->GetParam (i));
2467
+ }
2468
+ Vector<Value> values (stack_ + c->stack_depth , sig->parameter_count ());
2469
+ CALL_INTERFACE_IF_PARENT_REACHABLE (CatchException, imm, c, values);
2456
2470
current_code_reachable_ = this ->ok () && c->reachable ();
2457
- Value* exception = Push (kWasmExnRef );
2458
- CALL_INTERFACE_IF_PARENT_REACHABLE (Catch, c, exception);
2459
- return 1 ;
2471
+ return 1 + imm.length ;
2460
2472
}
2461
2473
2462
- DECODE (BrOnExn) {
2463
- CHECK_PROTOTYPE_OPCODE (eh);
2464
- BranchOnExceptionImmediate<validate> imm (this , this ->pc_ + 1 );
2465
- if (!this ->Validate (this ->pc () + 1 , imm, control_.size ())) return 0 ;
2466
- Control* c = control_at (imm.depth .depth );
2467
- Value exception = Pop (0 , kWasmExnRef );
2468
- const WasmExceptionSig* sig = imm.index .exception ->sig ;
2469
- int value_count = static_cast <int >(sig->parameter_count ());
2470
- // TODO(wasm): This operand stack mutation is an ugly hack to make
2471
- // both type checking here as well as environment merging in the
2472
- // graph builder interface work out of the box. We should introduce
2473
- // special handling for both and do minimal/no stack mutation here.
2474
- EnsureStackSpace (value_count);
2475
- for (int i = 0 ; i < value_count; ++i) Push (sig->GetParam (i));
2476
- Vector<Value> values (stack_ + c->stack_depth , value_count);
2477
- TypeCheckBranchResult check_result = TypeCheckBranch (c, true );
2478
- if (V8_LIKELY (check_result == kReachableBranch )) {
2479
- CALL_INTERFACE_IF_REACHABLE (BrOnException, exception, imm.index ,
2480
- imm.depth .depth , values);
2481
- c->br_merge ()->reached = true ;
2474
+ DECODE (CatchAll) {
2475
+ if (!VALIDATE (!control_.empty ())) {
2476
+ this ->error (" catch-all does not match any try" );
2477
+ return 0 ;
2482
2478
}
2483
- for (int i = value_count - 1 ; i >= 0 ; i--) Pop (i);
2484
- Value* pexception = Push (kWasmExnRef );
2485
- *pexception = exception;
2486
- return 1 + imm.length ;
2479
+ Control* c = &control_.back ();
2480
+ if (!VALIDATE (c->is_try ())) {
2481
+ this ->error (" catch-all does not match any try" );
2482
+ return 0 ;
2483
+ }
2484
+ if (!VALIDATE (!c->is_try_catchall ())) {
2485
+ this ->error (" catch-all already present for try" );
2486
+ return 0 ;
2487
+ }
2488
+ c->kind = kControlTryCatchAll ;
2489
+ FallThruTo (c);
2490
+ stack_end_ = stack_ + c->stack_depth ;
2491
+ c->reachability = control_at (1 )->innerReachability ();
2492
+ CALL_INTERFACE_IF_PARENT_REACHABLE (CatchAll, c);
2493
+ current_code_reachable_ = this ->ok () && c->reachable ();
2494
+ return 1 ;
2487
2495
}
2488
2496
2489
2497
DECODE (BrOnNull) {
@@ -2623,6 +2631,16 @@ class WasmFullDecoder : public WasmDecoder<validate> {
2623
2631
}
2624
2632
if (!TypeCheckOneArmedIf (c)) return 0 ;
2625
2633
}
2634
+ if (c->is_try_catch ()) {
2635
+ // Emulate catch-all + re-throw.
2636
+ FallThruTo (c);
2637
+ c->reachability = control_at (1 )->innerReachability ();
2638
+ CALL_INTERFACE_IF_PARENT_REACHABLE (CatchAll, c);
2639
+ current_code_reachable_ = this ->ok () && control_.back ().reachable ();
2640
+ CALL_INTERFACE_IF_REACHABLE (Rethrow, c);
2641
+ EndControl ();
2642
+ }
2643
+
2626
2644
if (c->is_let ()) {
2627
2645
this ->local_types_ .erase (this ->local_types_ .begin (),
2628
2646
this ->local_types_ .begin () + c->locals_count );
@@ -3197,7 +3215,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
3197
3215
DECODE_IMPL (Throw);
3198
3216
DECODE_IMPL (Try);
3199
3217
DECODE_IMPL (Catch);
3200
- DECODE_IMPL (BrOnExn );
3218
+ DECODE_IMPL (CatchAll );
3201
3219
DECODE_IMPL (BrOnNull);
3202
3220
DECODE_IMPL (Let);
3203
3221
DECODE_IMPL (Loop);
0 commit comments