@@ -1548,23 +1548,104 @@ class LiftoffCompiler {
15481548 wasm::ObjectAccess::ElementOffsetInTaggedFixedArray (
15491549 catch_case.maybe_tag .tag_imm .index ));
15501550
1551+ VarState exn = __ cache_state () -> stack_state.back ();
1552+
15511553 CODE_COMMENT (" compare tags" );
1552- {
1553- FREEZE_STATE (frozen);
1554- Label caught;
1555- __ emit_cond_jump (kEqual , &caught, kRefNull , imm_tag, caught_tag.gp (),
1556- frozen);
1557- // The tags don't match, merge the current state into the catch state
1558- // and jump to the next handler.
1559- __ MergeFullStackWith (block->try_info ->catch_state );
1560- __ emit_jump (&block->try_info ->catch_label );
1561- __ bind (&caught);
1554+ if (catch_case.maybe_tag .tag_imm .tag ->sig ->parameter_count () == 1 &&
1555+ catch_case.maybe_tag .tag_imm .tag ->sig ->GetParam (0 ) == kWasmExternRef ) {
1556+ // Check for the special case where the tag is WebAssembly.JSTag and the
1557+ // exception is not a WebAssembly.Exception. In this case the exception is
1558+ // caught and pushed on the operand stack.
1559+ // Only perform this check if the tag signature is the same as
1560+ // the JSTag signature, i.e. a single externref, otherwise we know
1561+ // statically that it cannot be the JSTag.
1562+ LiftoffRegister undefined =
1563+ pinned.set (__ GetUnusedRegister (kGpReg , pinned));
1564+ __ LoadFullPointer (
1565+ undefined.gp (), kRootRegister ,
1566+ IsolateData::root_slot_offset (RootIndex::kUndefinedValue ));
1567+ LiftoffRegister js_tag = pinned.set (__ GetUnusedRegister (kGpReg , pinned));
1568+ LOAD_TAGGED_PTR_INSTANCE_FIELD (js_tag.gp (), NativeContext, pinned);
1569+ __ LoadTaggedPointer (
1570+ js_tag.gp (), js_tag.gp (), no_reg,
1571+ NativeContext::SlotOffset (Context::WASM_JS_TAG_INDEX));
1572+ __ LoadTaggedPointer (
1573+ js_tag.gp (), js_tag.gp (), no_reg,
1574+ wasm::ObjectAccess::ToTagged (WasmTagObject::kTagOffset ));
1575+ {
1576+ LiftoffAssembler::CacheState initial_state (zone_);
1577+ LiftoffAssembler::CacheState end_state (zone_);
1578+ Label js_exception;
1579+ Label done;
1580+ Label uncaught;
1581+ initial_state.Split (*__ cache_state ());
1582+ {
1583+ FREEZE_STATE (state_merged_explicitly);
1584+ // If the tag is undefined, this is not a wasm exception. Go to a
1585+ // different block to process the JS exception. Otherwise compare it
1586+ // with the expected tag.
1587+ __ emit_cond_jump (kEqual , &js_exception, kRefNull , caught_tag.gp (),
1588+ undefined.gp (), state_merged_explicitly);
1589+ __ emit_cond_jump (kNotEqual , &uncaught, kRefNull , imm_tag,
1590+ caught_tag.gp (), state_merged_explicitly);
1591+ }
1592+ // Case 1: A wasm exception with a matching tag.
1593+ CODE_COMMENT (" unpack exception" );
1594+ GetExceptionValues (decoder, __ cache_state ()->stack_state .back (),
1595+ catch_case.maybe_tag .tag_imm .tag );
1596+ // GetExceptionValues modified the cache state. Remember the new state
1597+ // to merge the end state of case 2 into it.
1598+ end_state.Steal (*__ cache_state ());
1599+ __ emit_jump (&done);
1600+
1601+ __ bind (&js_exception);
1602+ __ cache_state () -> Split (initial_state);
1603+ {
1604+ FREEZE_STATE (state_merged_explicitly);
1605+ __ emit_cond_jump (kNotEqual , &uncaught, kRefNull , imm_tag,
1606+ js_tag.gp (), state_merged_explicitly);
1607+ }
1608+ // Case 2: A JS exception, and the expected tag is JSTag.
1609+ // TODO(thibaudm): Can we avoid some state splitting/stealing by
1610+ // reserving this register earlier and not modifying the state in this
1611+ // block?
1612+ CODE_COMMENT (" JS exception caught by JSTag" );
1613+ LiftoffRegister exception = __ PeekToRegister (0 , pinned);
1614+ __ PushRegister (kRefNull , exception);
1615+ // The exception is now on the stack twice: once as an implicit operand
1616+ // for rethrow, and once as the "unpacked" value.
1617+ __ MergeFullStackWith (end_state);
1618+ __ emit_jump (&done);
1619+
1620+ // Case 3: Either a wasm exception with a mismatching tag, or a JS
1621+ // exception but the expected tag is not JSTag.
1622+ __ bind (&uncaught);
1623+ __ cache_state () -> Steal (initial_state);
1624+ __ MergeFullStackWith (block->try_info ->catch_state );
1625+ __ emit_jump (&block->try_info ->catch_label );
1626+
1627+ __ bind (&done);
1628+ __ cache_state () -> Steal (end_state);
1629+ }
1630+ } else {
1631+ {
1632+ FREEZE_STATE (frozen);
1633+ Label caught;
1634+ __ emit_cond_jump (kEqual , &caught, kRefNull , imm_tag, caught_tag.gp (),
1635+ frozen);
1636+ // The tags don't match, merge the current state into the catch state
1637+ // and jump to the next handler.
1638+ __ MergeFullStackWith (block->try_info ->catch_state );
1639+ __ emit_jump (&block->try_info ->catch_label );
1640+ __ bind (&caught);
1641+ }
1642+
1643+ CODE_COMMENT (" unpack exception" );
1644+ pinned = {};
1645+ GetExceptionValues (decoder, __ cache_state ()->stack_state .back (),
1646+ catch_case.maybe_tag .tag_imm .tag );
15621647 }
15631648
1564- CODE_COMMENT (" unpack exception" );
1565- pinned = {};
1566- VarState exn = __ cache_state ()->stack_state .back ();
1567- GetExceptionValues (decoder, exn, catch_case.maybe_tag .tag_imm .tag );
15681649 if (catch_case.kind == kCatchRef ) {
15691650 // Append the exception on the operand stack.
15701651 DCHECK (exn.is_stack ());
0 commit comments