Skip to content

Commit 6ed9e61

Browse files
sjrdguybedford
authored andcommitted
deps: V8: cherry-pick 692f3d526a38
Original commit message: [wasm][exnref] Implement special behavior of WA.JSTag in try_table. This commit ports the changes from 4e79015dc28659a8a031f06580e902720b35674c to `CatchCase`, i.e., the `try_table` instruction. In addition, it implements the same changes in Turboshaft, for which the implementation of exceptions initially came from 2c1c14d30c61fa4fa19184369e587cb663bd8580 and already contained the `JSTag` handling for `CatchException`. This commit addresses part of https://issues.chromium.org/issues/333067164 but not all. Only catching with `try_table` is fixed. `throw` remains unchanged. Change-Id: I7bad031e28eaf609fb12e7706d0b6a7cc63fa09d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5435077 Commit-Queue: Thibaud Michaud <[email protected]> Reviewed-by: Thibaud Michaud <[email protected]> Cr-Commit-Position: refs/heads/main@{#93303} Refs: v8/v8@692f3d5
1 parent 82e371c commit 6ed9e61

7 files changed

Lines changed: 416 additions & 28 deletions

File tree

common.gypi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
# Reset this number to 0 on major V8 upgrades.
4040
# Increment by one for each non-official patch applied to deps/v8.
41-
'v8_embedder_string': '-node.42',
41+
'v8_embedder_string': '-node.43',
4242

4343
##### V8 defaults for Node.js #####
4444

deps/v8/AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ Sander Mathijs van Veen <[email protected]>
258258
Sandro Santilli <[email protected]>
259259
Sanjoy Das <[email protected]>
260260
Sam James <[email protected]>
261+
Sébastien Doeraene <[email protected]>
261262
Seo Sanghyeon <[email protected]>
262263
Shawn Anastasio <[email protected]>
263264
Shawn Presser <[email protected]>

deps/v8/src/wasm/baseline/liftoff-compiler.cc

Lines changed: 95 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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());

deps/v8/src/wasm/graph-builder-interface.cc

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,9 +1420,58 @@ class WasmGraphBuildingInterface {
14201420
base::Vector<Value> values_without_exnref =
14211421
catch_case.kind == kCatch ? values
14221422
: values.SubVector(0, values.size() - 1);
1423-
CatchAndUnpackWasmException(decoder, block, exception,
1424-
catch_case.maybe_tag.tag_imm.tag, caught_tag,
1425-
expected_tag, values_without_exnref);
1423+
1424+
if (catch_case.maybe_tag.tag_imm.tag->sig->parameter_count() == 1 &&
1425+
catch_case.maybe_tag.tag_imm.tag->sig->GetParam(0) == kWasmExternRef) {
1426+
// Check for the special case where the tag is WebAssembly.JSTag and the
1427+
// exception is not a WebAssembly.Exception. In this case the exception is
1428+
// caught and pushed on the operand stack.
1429+
// Only perform this check if the tag signature is the same as
1430+
// the JSTag signature, i.e. a single externref, otherwise
1431+
// we know statically that it cannot be the JSTag.
1432+
1433+
TFNode* is_js_exn = builder_->IsExceptionTagUndefined(caught_tag);
1434+
auto [exn_is_js, exn_is_wasm] = builder_->BranchExpectFalse(is_js_exn);
1435+
SsaEnv* exn_is_js_env = Split(decoder->zone(), ssa_env_);
1436+
exn_is_js_env->control = exn_is_js;
1437+
SsaEnv* exn_is_wasm_env = Steal(decoder->zone(), ssa_env_);
1438+
exn_is_wasm_env->control = exn_is_wasm;
1439+
1440+
// Case 1: A wasm exception.
1441+
SetEnv(exn_is_wasm_env);
1442+
CatchAndUnpackWasmException(decoder, block, exception,
1443+
catch_case.maybe_tag.tag_imm.tag, caught_tag,
1444+
expected_tag, values_without_exnref);
1445+
1446+
// Case 2: A JS exception.
1447+
SetEnv(exn_is_js_env);
1448+
TFNode* js_tag = builder_->LoadJSTag();
1449+
TFNode* compare = builder_->ExceptionTagEqual(expected_tag, js_tag);
1450+
auto [if_catch, if_no_catch] = builder_->BranchNoHint(compare);
1451+
// Merge the wasm no-catch and JS no-catch paths.
1452+
SsaEnv* if_no_catch_env = Split(decoder->zone(), ssa_env_);
1453+
if_no_catch_env->control = if_no_catch;
1454+
SetEnv(if_no_catch_env);
1455+
Goto(decoder, block->try_info->catch_env);
1456+
// Merge the wasm catch and JS catch paths.
1457+
SsaEnv* if_catch_env = Steal(decoder->zone(), ssa_env_);
1458+
if_catch_env->control = if_catch;
1459+
SetEnv(if_catch_env);
1460+
Goto(decoder, block->block_env);
1461+
1462+
// The final env is a merge of case 1 and 2. The unpacked value is a Phi
1463+
// of the unpacked value (case 1) and the exception itself (case 2).
1464+
SetEnv(block->block_env);
1465+
TFNode* phi_inputs[] = {values[0].node, exception,
1466+
block->block_env->control};
1467+
TFNode* ref = builder_->Phi(wasm::kWasmExternRef, 2, phi_inputs);
1468+
SetAndTypeNode(&values[0], ref);
1469+
} else {
1470+
CatchAndUnpackWasmException(decoder, block, exception,
1471+
catch_case.maybe_tag.tag_imm.tag, caught_tag,
1472+
expected_tag, values_without_exnref);
1473+
}
1474+
14261475
if (catch_case.kind == kCatchRef) {
14271476
DCHECK_EQ(values.last().type, kWasmExnRef);
14281477
values.last().node = block->try_info->exception;

deps/v8/src/wasm/turboshaft-graph-interface.cc

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3010,9 +3010,10 @@ class TurboshaftGraphBuildingInterface : public WasmGraphBuilderBase {
30103010
BrOrRet(decoder, catch_case.br_imm.depth);
30113011
return;
30123012
}
3013+
V<NativeContext> native_context = instance_cache_.native_context();
30133014
V<WasmTagObject> caught_tag = V<WasmTagObject>::Cast(
30143015
CallBuiltinThroughJumptable<BuiltinCallDescriptor::WasmGetOwnProperty>(
3015-
decoder, instance_cache_.native_context(),
3016+
decoder, native_context,
30163017
{block->exception, LOAD_ROOT(wasm_exception_tag_symbol)}));
30173018
V<FixedArray> instance_tags =
30183019
LOAD_IMMUTABLE_INSTANCE_FIELD(trusted_instance_data(), TagsTable,
@@ -3022,17 +3023,70 @@ class TurboshaftGraphBuildingInterface : public WasmGraphBuilderBase {
30223023
TSBlock* if_catch = __ NewBlock();
30233024
TSBlock* if_no_catch = NewBlockWithPhis(decoder, nullptr);
30243025
SetupControlFlowEdge(decoder, if_no_catch);
3026+
3027+
// If the tags don't match we continue with the next tag by setting the
3028+
// no-catch environment as the new {block->false_or_loop_or_catch_block}
3029+
// here.
30253030
block->false_or_loop_or_catch_block = if_no_catch;
3026-
__ Branch(ConditionWithHint(__ TaggedEqual(caught_tag, expected_tag)),
3027-
if_catch, block->false_or_loop_or_catch_block);
3028-
__ Bind(if_catch);
3029-
if (catch_case.kind == kCatchRef) {
3030-
UnpackWasmException(decoder, block->exception,
3031-
values.SubVector(0, values.size() - 1));
3032-
values.last().op = block->exception;
3031+
3032+
if (catch_case.maybe_tag.tag_imm.tag->sig->parameter_count() == 1 &&
3033+
catch_case.maybe_tag.tag_imm.tag->sig->GetParam(0) == kWasmExternRef) {
3034+
// Check for the special case where the tag is WebAssembly.JSTag and the
3035+
// exception is not a WebAssembly.Exception. In this case the exception is
3036+
// caught and pushed on the operand stack.
3037+
// Only perform this check if the tag signature is the same as
3038+
// the JSTag signature, i.e. a single externref, otherwise
3039+
// we know statically that it cannot be the JSTag.
3040+
V<Word32> caught_tag_undefined =
3041+
__ TaggedEqual(caught_tag, LOAD_ROOT(UndefinedValue));
3042+
Label<Object> if_catch(&asm_);
3043+
Label<> no_catch_merge(&asm_);
3044+
3045+
IF (UNLIKELY(caught_tag_undefined)) {
3046+
V<Object> tag_object = __ Load(
3047+
native_context, LoadOp::Kind::TaggedBase(),
3048+
MemoryRepresentation::TaggedPointer(),
3049+
NativeContext::OffsetOfElementAt(Context::WASM_JS_TAG_INDEX));
3050+
V<Object> js_tag = __ Load(tag_object, LoadOp::Kind::TaggedBase(),
3051+
MemoryRepresentation::TaggedPointer(),
3052+
WasmTagObject::kTagOffset);
3053+
GOTO_IF(__ TaggedEqual(expected_tag, js_tag), if_catch,
3054+
block->exception);
3055+
GOTO(no_catch_merge);
3056+
} ELSE {
3057+
IF (__ TaggedEqual(caught_tag, expected_tag)) {
3058+
if (catch_case.kind == kCatchRef) {
3059+
UnpackWasmException(decoder, block->exception,
3060+
values.SubVector(0, values.size() - 1));
3061+
values.last().op = block->exception;
3062+
} else {
3063+
UnpackWasmException(decoder, block->exception, values);
3064+
}
3065+
GOTO(if_catch, values[0].op);
3066+
}
3067+
GOTO(no_catch_merge);
3068+
}
3069+
3070+
BIND(no_catch_merge);
3071+
__ Goto(if_no_catch);
3072+
3073+
BIND(if_catch, caught_exception);
3074+
// The first unpacked value is the exception itself in the case of a JS
3075+
// exception.
3076+
values[0].op = caught_exception;
30333077
} else {
3034-
UnpackWasmException(decoder, block->exception, values);
3078+
__ Branch(ConditionWithHint(__ TaggedEqual(caught_tag, expected_tag)),
3079+
if_catch, if_no_catch);
3080+
__ Bind(if_catch);
3081+
if (catch_case.kind == kCatchRef) {
3082+
UnpackWasmException(decoder, block->exception,
3083+
values.SubVector(0, values.size() - 1));
3084+
values.last().op = block->exception;
3085+
} else {
3086+
UnpackWasmException(decoder, block->exception, values);
3087+
}
30353088
}
3089+
30363090
BrOrRet(decoder, catch_case.br_imm.depth);
30373091

30383092
bool is_last = &catch_case == &block->catch_cases.last();

0 commit comments

Comments
 (0)