Skip to content

Commit 841c7c1

Browse files
LiedtkeV8 LUCI CQ
authored andcommitted
[wasm] Introduce new heap type 'imported string'
This heap type does not exist in the wasm spec. It is used as an internal type to mark externref values in our optimizations for which we know that it is a (potentially nullable) JS string. Previously the wasm string type from the stringref proposal was used for that. This can cause all kinds of issues as ref.string is a subtype of any, not extern. (It also uses a different null representation.) Fixed: chromium:324747822 Change-Id: I9cc2975b8612510de18e02d3b66ed54489d9cc22 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5293801 Reviewed-by: Jakob Kummerow <[email protected]> Commit-Queue: Matthias Liedtke <[email protected]> Cr-Commit-Position: refs/heads/main@{#92348}
1 parent a873287 commit 841c7c1

File tree

6 files changed

+136
-47
lines changed

6 files changed

+136
-47
lines changed

src/compiler/turboshaft/wasm-gc-type-reducer.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ class WasmGCTypeReducer : public Next {
137137

138138
wasm::ValueType type = analyzer_.GetInputType(op_idx);
139139
if (type != wasm::ValueType() && !type.is_uninhabited()) {
140+
DCHECK(wasm::IsSameTypeHierarchy(type.heap_type(),
141+
cast_op.config.to.heap_type(), module_));
140142
bool to_nullable = cast_op.config.to.is_nullable();
141143
if (wasm::IsHeapSubtypeOf(type.heap_type(), cast_op.config.to.heap_type(),
142144
module_, module_)) {
@@ -154,8 +156,7 @@ class WasmGCTypeReducer : public Next {
154156
}
155157
if (wasm::HeapTypesUnrelated(type.heap_type(),
156158
cast_op.config.to.heap_type(), module_,
157-
module_) &&
158-
!wasm::IsImplicitInternalization(type, cast_op.config.to, module_)) {
159+
module_)) {
159160
// A cast between unrelated types can only succeed if the argument is
160161
// null. Otherwise, it always fails.
161162
V<Word32> non_trapping_condition =
@@ -191,6 +192,8 @@ class WasmGCTypeReducer : public Next {
191192

192193
wasm::ValueType type = analyzer_.GetInputType(op_idx);
193194
if (type != wasm::ValueType() && !type.is_uninhabited()) {
195+
DCHECK(wasm::IsSameTypeHierarchy(
196+
type.heap_type(), type_check.config.to.heap_type(), module_));
194197
bool to_nullable = type_check.config.to.is_nullable();
195198
if (wasm::IsHeapSubtypeOf(type.heap_type(),
196199
type_check.config.to.heap_type(), module_,
@@ -208,9 +211,7 @@ class WasmGCTypeReducer : public Next {
208211
}
209212
if (wasm::HeapTypesUnrelated(type.heap_type(),
210213
type_check.config.to.heap_type(), module_,
211-
module_) &&
212-
!wasm::IsImplicitInternalization(type, type_check.config.to,
213-
module_)) {
214+
module_)) {
214215
if (to_nullable && type.is_nullable()) {
215216
return __ IsNull(__ MapToNewGraph(type_check.object()), type);
216217
} else {

src/compiler/turboshaft/wasm-lowering-reducer.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,8 @@ class WasmLoweringReducer : public Next {
595595
result = __ HasInstanceType(object, WASM_STRUCT_TYPE);
596596
break;
597597
}
598-
if (to_rep == wasm::HeapType::kString) {
598+
if (to_rep == wasm::HeapType::kString ||
599+
to_rep == wasm::HeapType::kExternString) {
599600
V<Word32> instance_type =
600601
__ LoadInstanceTypeField(__ LoadMapField(object));
601602
result = __ Uint32LessThan(instance_type,
@@ -671,7 +672,8 @@ class WasmLoweringReducer : public Next {
671672
OpIndex::Invalid(), TrapId::kTrapIllegalCast);
672673
break;
673674
}
674-
if (to_rep == wasm::HeapType::kString) {
675+
if (to_rep == wasm::HeapType::kString ||
676+
to_rep == wasm::HeapType::kExternString) {
675677
V<Word32> instance_type =
676678
__ LoadInstanceTypeField(__ LoadMapField(object));
677679
__ TrapIfNot(__ Uint32LessThan(instance_type,

src/wasm/turboshaft-graph-interface.cc

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,14 +1067,14 @@ class TurboshaftGraphBuildingInterface {
10671067
}
10681068

10691069
V<Word32> IsExternRefString(const Value value) {
1070-
compiler::WasmTypeCheckConfig config{value.type, kWasmRefString};
1070+
compiler::WasmTypeCheckConfig config{value.type, kWasmRefExternString};
10711071
V<Map> rtt = OpIndex::Invalid();
10721072
return __ WasmTypeCheck(value.op, rtt, config);
10731073
}
10741074

10751075
V<String> ExternRefToString(const Value value, bool null_succeeds = false) {
10761076
wasm::ValueType target_type =
1077-
null_succeeds ? kWasmStringRef : kWasmRefString;
1077+
null_succeeds ? kWasmRefNullExternString : kWasmRefExternString;
10781078
compiler::WasmTypeCheckConfig config{value.type, target_type};
10791079
V<Map> rtt = OpIndex::Invalid();
10801080
return V<String>::Cast(__ WasmTypeCast(value.op, rtt, config));
@@ -1084,7 +1084,7 @@ class TurboshaftGraphBuildingInterface {
10841084
if (__ generating_unreachable_operations()) return false;
10851085
const WasmTypeCastOp* cast =
10861086
__ output_graph().Get(value.op).TryCast<WasmTypeCastOp>();
1087-
return cast && cast->config.to == kWasmRefString;
1087+
return cast && cast->config.to == kWasmRefExternString;
10881088
}
10891089

10901090
V<Word32> GetStringIndexOf(FullDecoder* decoder, V<String> string,
@@ -1155,7 +1155,7 @@ class TurboshaftGraphBuildingInterface {
11551155
BuiltinCallDescriptor::StringToLowerCaseIntl>(
11561156
decoder, __ NoContextConstant(), {string});
11571157
BuildModifyThreadInWasmFlag(decoder, true);
1158-
return __ AnnotateWasmType(result, kWasmRefString);
1158+
return result;
11591159
}
11601160
#endif
11611161

@@ -1403,6 +1403,19 @@ class TurboshaftGraphBuildingInterface {
14031403
GetExternalArrayType(op_type));
14041404
}
14051405

1406+
// Adds a wasm type annotation to the graph and replaces any extern type with
1407+
// the extern string type.
1408+
V<String> AnnotateAsString(OpIndex value, wasm::ValueType type) {
1409+
DCHECK(type.is_reference_to(HeapType::kString) ||
1410+
type.is_reference_to(HeapType::kExternString) ||
1411+
type.is_reference_to(HeapType::kExtern));
1412+
if (type.is_reference_to(HeapType::kExtern)) {
1413+
type =
1414+
ValueType::RefMaybeNull(HeapType::kExternString, type.nullability());
1415+
}
1416+
return __ AnnotateWasmType(value, type);
1417+
}
1418+
14061419
bool HandleWellKnownImport(FullDecoder* decoder, uint32_t index,
14071420
const Value args[], Value returns[]) {
14081421
if (!decoder->module_) return false; // Only needed for tests.
@@ -1461,7 +1474,7 @@ class TurboshaftGraphBuildingInterface {
14611474
BuiltinCallDescriptor::StringAdd_CheckNone>(
14621475
decoder, V<Context>::Cast(native_context),
14631476
{head_string, tail_string});
1464-
result = __ AnnotateWasmType(result, kWasmRefString);
1477+
result = __ AnnotateWasmType(result, kWasmRefExternString);
14651478
decoder->detected_->Add(kFeature_imported_strings);
14661479
break;
14671480
}
@@ -1480,7 +1493,7 @@ class TurboshaftGraphBuildingInterface {
14801493
V<Word32> capped = __ Word32BitwiseAnd(args[0].op, 0xFFFF);
14811494
result = CallBuiltinThroughJumptable<
14821495
BuiltinCallDescriptor::WasmStringFromCodePoint>(decoder, {capped});
1483-
result = __ AnnotateWasmType(result, kWasmRefString);
1496+
result = __ AnnotateWasmType(result, kWasmRefExternString);
14841497
decoder->detected_->Add(kFeature_imported_strings);
14851498
break;
14861499
}
@@ -1489,21 +1502,21 @@ class TurboshaftGraphBuildingInterface {
14891502
result = CallBuiltinThroughJumptable<
14901503
BuiltinCallDescriptor::WasmStringFromCodePoint>(decoder,
14911504
{args[0].op});
1492-
result = __ AnnotateWasmType(result, kWasmRefString);
1505+
result = __ AnnotateWasmType(result, kWasmRefExternString);
14931506
decoder->detected_->Add(kFeature_imported_strings);
14941507
break;
14951508
case WKI::kStringFromWtf16Array:
14961509
result = CallBuiltinThroughJumptable<
14971510
BuiltinCallDescriptor::WasmStringNewWtf16Array>(
14981511
decoder,
14991512
{V<WasmArray>::Cast(NullCheck(args[0])), args[1].op, args[2].op});
1500-
result = __ AnnotateWasmType(result, kWasmRefString);
1513+
result = __ AnnotateWasmType(result, kWasmRefExternString);
15011514
decoder->detected_->Add(kFeature_imported_strings);
15021515
break;
15031516
case WKI::kStringFromUtf8Array:
1504-
result =
1505-
StringNewWtf8ArrayImpl(decoder, unibrow::Utf8Variant::kLossyUtf8,
1506-
args[0], args[1], args[2]);
1517+
result = StringNewWtf8ArrayImpl(
1518+
decoder, unibrow::Utf8Variant::kLossyUtf8, args[0], args[1],
1519+
args[2], kWasmRefExternString);
15071520
decoder->detected_->Add(kFeature_imported_strings);
15081521
break;
15091522
case WKI::kStringIntoUtf8Array: {
@@ -1544,7 +1557,7 @@ class TurboshaftGraphBuildingInterface {
15441557
result = CallBuiltinThroughJumptable<
15451558
BuiltinCallDescriptor::WasmStringViewWtf16Slice>(
15461559
decoder, {V<String>::Cast(view), args[1].op, args[2].op});
1547-
result = __ AnnotateWasmType(result, kWasmRefString);
1560+
result = __ AnnotateWasmType(result, kWasmRefExternString);
15481561
decoder->detected_->Add(kFeature_imported_strings);
15491562
break;
15501563
}
@@ -1563,7 +1576,7 @@ class TurboshaftGraphBuildingInterface {
15631576
BuildModifyThreadInWasmFlag(decoder, false);
15641577
result = CallBuiltinThroughJumptable<
15651578
BuiltinCallDescriptor::WasmFloat64ToString>(decoder, {args[0].op});
1566-
result = __ AnnotateWasmType(result, kWasmRefString);
1579+
result = AnnotateAsString(result, returns[0].type);
15671580
BuildModifyThreadInWasmFlag(decoder, true);
15681581
decoder->detected_->Add(
15691582
returns[0].type.is_reference_to(wasm::HeapType::kString)
@@ -1575,7 +1588,7 @@ class TurboshaftGraphBuildingInterface {
15751588
result =
15761589
CallBuiltinThroughJumptable<BuiltinCallDescriptor::WasmIntToString>(
15771590
decoder, {args[0].op, args[1].op});
1578-
result = __ AnnotateWasmType(result, kWasmRefString);
1591+
result = AnnotateAsString(result, returns[0].type);
15791592
BuildModifyThreadInWasmFlag(decoder, true);
15801593
decoder->detected_->Add(
15811594
returns[0].type.is_reference_to(wasm::HeapType::kString)
@@ -1585,7 +1598,7 @@ class TurboshaftGraphBuildingInterface {
15851598
case WKI::kParseFloat: {
15861599
if (args[0].type.is_nullable()) {
15871600
Label<Float64> done(&asm_);
1588-
GOTO_IF(__ IsNull(args[0].op, wasm::kWasmStringRef), done,
1601+
GOTO_IF(__ IsNull(args[0].op, args[0].type), done,
15891602
__ Float64Constant(std::numeric_limits<double>::quiet_NaN()));
15901603

15911604
BuildModifyThreadInWasmFlag(decoder, false);
@@ -1612,7 +1625,7 @@ class TurboshaftGraphBuildingInterface {
16121625

16131626
// If string is null, throw.
16141627
if (args[0].type.is_nullable()) {
1615-
IF (__ IsNull(string, wasm::kWasmStringRef)) {
1628+
IF (__ IsNull(string, args[0].type)) {
16161629
CallBuiltinThroughJumptable<
16171630
BuiltinCallDescriptor::ThrowIndexOfCalledOnNull>(decoder, {});
16181631
__ Unreachable();
@@ -1623,8 +1636,8 @@ class TurboshaftGraphBuildingInterface {
16231636
// If search is null, replace it with "null".
16241637
if (args[1].type.is_nullable()) {
16251638
Label<String> search_done_label(&asm_);
1626-
GOTO_IF_NOT(__ IsNull(search, wasm::kWasmStringRef),
1627-
search_done_label, search);
1639+
GOTO_IF_NOT(__ IsNull(search, args[1].type), search_done_label,
1640+
search);
16281641
GOTO(search_done_label, LOAD_ROOT(null_string));
16291642
BIND(search_done_label, search_value);
16301643
search = search_value;
@@ -1656,7 +1669,7 @@ class TurboshaftGraphBuildingInterface {
16561669
#if V8_INTL_SUPPORT
16571670
V<String> string = args[0].op;
16581671
if (args[0].type.is_nullable()) {
1659-
IF (__ IsNull(string, wasm::kWasmStringRef)) {
1672+
IF (__ IsNull(string, args[0].type)) {
16601673
CallBuiltinThroughJumptable<
16611674
BuiltinCallDescriptor::ThrowToLowerCaseCalledOnNull>(decoder,
16621675
{});
@@ -1665,6 +1678,7 @@ class TurboshaftGraphBuildingInterface {
16651678
END_IF
16661679
}
16671680
result = CallStringToLowercase(decoder, string);
1681+
__ AnnotateWasmType(result, kWasmRefString);
16681682
decoder->detected_->Add(kFeature_stringref);
16691683
break;
16701684
#else
@@ -1681,6 +1695,7 @@ class TurboshaftGraphBuildingInterface {
16811695
}
16821696
V<String> string = args[0].op;
16831697
result = CallStringToLowercase(decoder, string);
1698+
__ AnnotateWasmType(result, kWasmRefExternString);
16841699
decoder->detected_->Add(kFeature_imported_strings);
16851700
break;
16861701
#else
@@ -3347,7 +3362,7 @@ class TurboshaftGraphBuildingInterface {
33473362
V<Tagged> StringNewWtf8ArrayImpl(FullDecoder* decoder,
33483363
const unibrow::Utf8Variant variant,
33493364
const Value& array, const Value& start,
3350-
const Value& end) {
3365+
const Value& end, ValueType result_type) {
33513366
// Special case: shortcut a sequence "array from data segment" + "string
33523367
// from wtf8 array" to directly create a string from the segment.
33533368
V<Tagged> call;
@@ -3379,16 +3394,20 @@ class TurboshaftGraphBuildingInterface {
33793394
{start.op, end.op, V<WasmArray>::Cast(NullCheck(array)),
33803395
__ SmiConstant(Smi::FromInt(static_cast<int32_t>(variant)))});
33813396
}
3382-
bool null_on_invalid = variant == unibrow::Utf8Variant::kUtf8NoTrap;
3383-
return __ AnnotateWasmType(
3384-
call, null_on_invalid ? kWasmStringRef : kWasmRefString);
3397+
DCHECK_IMPLIES(variant == unibrow::Utf8Variant::kUtf8NoTrap,
3398+
result_type.is_nullable());
3399+
// The builtin returns a WasmNull for kUtf8NoTrap, so nullable values in
3400+
// combination with extern strings are not supported.
3401+
DCHECK_NE(result_type, wasm::kWasmExternRef);
3402+
return AnnotateAsString(call, result_type);
33853403
}
33863404

33873405
void StringNewWtf8Array(FullDecoder* decoder,
33883406
const unibrow::Utf8Variant variant,
33893407
const Value& array, const Value& start,
33903408
const Value& end, Value* result) {
3391-
result->op = StringNewWtf8ArrayImpl(decoder, variant, array, start, end);
3409+
result->op = StringNewWtf8ArrayImpl(decoder, variant, array, start, end,
3410+
result->type);
33923411
}
33933412

33943413
void StringNewWtf16(FullDecoder* decoder, const MemoryIndexImmediate& imm,

src/wasm/value-type.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class HeapType {
6666
kArray, // shorthand: g
6767
kAny, //
6868
kExtern, // shorthand: a.
69+
kExternString, // Internal type for optimization purposes.
70+
// Subtype of extern.
71+
// Used by the js-builtin-strings proposal.
6972
kExn, //
7073
kString, // shorthand: w.
7174
kStringViewWtf8, // shorthand: x.
@@ -172,6 +175,8 @@ class HeapType {
172175
return std::string("array");
173176
case kExtern:
174177
return std::string("extern");
178+
case kExternString:
179+
return std::string("<extern_string>");
175180
case kAny:
176181
return std::string("any");
177182
case kString:
@@ -745,6 +750,10 @@ constexpr ValueType kWasmStructRef = ValueType::RefNull(HeapType::kStruct);
745750
constexpr ValueType kWasmArrayRef = ValueType::RefNull(HeapType::kArray);
746751
constexpr ValueType kWasmStringRef = ValueType::RefNull(HeapType::kString);
747752
constexpr ValueType kWasmRefString = ValueType::Ref(HeapType::kString);
753+
constexpr ValueType kWasmRefNullExternString =
754+
ValueType::RefNull(HeapType::kExternString);
755+
constexpr ValueType kWasmRefExternString =
756+
ValueType::Ref(HeapType::kExternString);
748757
constexpr ValueType kWasmStringViewWtf8 =
749758
ValueType::RefNull(HeapType::kStringViewWtf8);
750759
constexpr ValueType kWasmStringViewWtf16 =

0 commit comments

Comments
 (0)