Commit 8366df73 authored by Andy Wingo's avatar Andy Wingo Committed by V8 LUCI CQ

[stringrefs] Fold wtf8 policy into instruction set

Instead of having e.g. `string.new_wtf8` that takes an immediate
specifying the particular UTF-8 flavor to parse, make one instruction
per flavor.

See https://github.com/WebAssembly/stringref/pull/46.

Bug: v8:12868
Change-Id: I2e9f2735c557b2352b6e75314037e473710d87a9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3892695Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Andy Wingo <wingo@igalia.com>
Cr-Commit-Position: refs/heads/main@{#83170}
parent 6946d1de
......@@ -808,20 +808,20 @@ transitioning javascript builtin ExperimentalWasmConvertStringToArray(
}
builtin WasmStringNewWtf8(
offset: uint32, size: uint32, memory: Smi, policy: Smi): String {
offset: uint32, size: uint32, memory: Smi, utf8Variant: Smi): String {
const instance = LoadInstanceFromFrame();
tail runtime::WasmStringNewWtf8(
LoadContextFromInstance(instance), instance, memory, policy,
LoadContextFromInstance(instance), instance, memory, utf8Variant,
WasmUint32ToNumber(offset), WasmUint32ToNumber(size));
}
builtin WasmStringNewWtf8Array(
start: uint32, end: uint32, array: WasmArray, policy: Smi): String {
start: uint32, end: uint32, array: WasmArray, utf8Variant: Smi): String {
const context = LoadContextFromFrame();
try {
if (array.length < end) goto OffsetOutOfRange;
if (end < start) goto OffsetOutOfRange;
tail runtime::WasmStringNewWtf8Array(
context, policy, array, SmiFromUint32(start), SmiFromUint32(end));
context, utf8Variant, array, SmiFromUint32(start), SmiFromUint32(end));
} label OffsetOutOfRange deferred {
const error = MessageTemplate::kWasmTrapArrayOutOfBounds;
runtime::ThrowWasmError(context, SmiConstant(error));
......@@ -863,18 +863,18 @@ builtin WasmStringMeasureWtf8(string: String): int32 {
return Signed(ChangeNumberToUint32(result));
}
builtin WasmStringEncodeWtf8(
string: String, offset: uint32, memory: Smi, policy: Smi): uint32 {
string: String, offset: uint32, memory: Smi, utf8Variant: Smi): uint32 {
const instance = LoadInstanceFromFrame();
const result = runtime::WasmStringEncodeWtf8(
LoadContextFromInstance(instance), instance, memory, policy, string,
LoadContextFromInstance(instance), instance, memory, utf8Variant, string,
WasmUint32ToNumber(offset));
return ChangeNumberToUint32(result);
}
builtin WasmStringEncodeWtf8Array(
string: String, array: WasmArray, start: uint32, policy: Smi): uint32 {
string: String, array: WasmArray, start: uint32, utf8Variant: Smi): uint32 {
const instance = LoadInstanceFromFrame();
const result = runtime::WasmStringEncodeWtf8Array(
LoadContextFromInstance(instance), policy, string, array,
LoadContextFromInstance(instance), utf8Variant, string, array,
WasmUint32ToNumber(start));
return ChangeNumberToUint32(result);
}
......@@ -985,7 +985,7 @@ struct NewPositionAndBytesWritten {
}
builtin WasmStringViewWtf8Encode(
addr: uint32, pos: uint32, bytes: uint32, view: ByteArray, memory: Smi,
policy: Smi): NewPositionAndBytesWritten {
utf8Variant: Smi): NewPositionAndBytesWritten {
const start = WasmStringViewWtf8Advance(view, pos, 0);
const end = WasmStringViewWtf8Advance(view, start, bytes);
const instance = LoadInstanceFromFrame();
......@@ -999,7 +999,7 @@ builtin WasmStringViewWtf8Encode(
// Always call out to run-time, to catch invalid addr.
runtime::WasmStringViewWtf8Encode(
context, instance, policy, view, WasmUint32ToNumber(addr),
context, instance, utf8Variant, view, WasmUint32ToNumber(addr),
WasmUint32ToNumber(start), WasmUint32ToNumber(end));
return NewPositionAndBytesWritten{
......
......@@ -5732,19 +5732,19 @@ void WasmGraphBuilder::ArrayCopy(Node* dst_array, Node* dst_index,
}
Node* WasmGraphBuilder::StringNewWtf8(uint32_t memory,
wasm::StringRefWtf8Policy policy,
unibrow::Utf8Variant variant,
Node* offset, Node* size) {
return gasm_->CallBuiltin(Builtin::kWasmStringNewWtf8, Operator::kNoDeopt,
offset, size, gasm_->SmiConstant(memory),
gasm_->SmiConstant(static_cast<int32_t>(policy)));
gasm_->SmiConstant(static_cast<int32_t>(variant)));
}
Node* WasmGraphBuilder::StringNewWtf8Array(wasm::StringRefWtf8Policy policy,
Node* WasmGraphBuilder::StringNewWtf8Array(unibrow::Utf8Variant variant,
Node* array, Node* start,
Node* end) {
return gasm_->CallBuiltin(Builtin::kWasmStringNewWtf8Array,
Operator::kNoDeopt, start, end, array,
gasm_->SmiConstant(static_cast<int32_t>(policy)));
gasm_->SmiConstant(static_cast<int32_t>(variant)));
}
Node* WasmGraphBuilder::StringNewWtf16(uint32_t memory, Node* offset,
......@@ -5794,7 +5794,7 @@ Node* WasmGraphBuilder::StringMeasureWtf16(Node* string,
}
Node* WasmGraphBuilder::StringEncodeWtf8(uint32_t memory,
wasm::StringRefWtf8Policy policy,
unibrow::Utf8Variant variant,
Node* string, CheckForNull null_check,
Node* offset,
wasm::WasmCodePosition position) {
......@@ -5803,13 +5803,13 @@ Node* WasmGraphBuilder::StringEncodeWtf8(uint32_t memory,
}
return gasm_->CallBuiltin(Builtin::kWasmStringEncodeWtf8, Operator::kNoDeopt,
string, offset, gasm_->SmiConstant(memory),
gasm_->SmiConstant(policy));
gasm_->SmiConstant(static_cast<int32_t>(variant)));
}
Node* WasmGraphBuilder::StringEncodeWtf8Array(
wasm::StringRefWtf8Policy policy, Node* string,
CheckForNull string_null_check, Node* array, CheckForNull array_null_check,
Node* start, wasm::WasmCodePosition position) {
unibrow::Utf8Variant variant, Node* string, CheckForNull string_null_check,
Node* array, CheckForNull array_null_check, Node* start,
wasm::WasmCodePosition position) {
if (string_null_check == kWithNullCheck) {
string = AssertNotNull(string, position);
}
......@@ -5818,7 +5818,7 @@ Node* WasmGraphBuilder::StringEncodeWtf8Array(
}
return gasm_->CallBuiltin(Builtin::kWasmStringEncodeWtf8Array,
Operator::kNoDeopt, string, array, start,
gasm_->SmiConstant(policy));
gasm_->SmiConstant(static_cast<int32_t>(variant)));
}
Node* WasmGraphBuilder::StringEncodeWtf16(uint32_t memory, Node* string,
......@@ -5900,15 +5900,16 @@ Node* WasmGraphBuilder::StringViewWtf8Advance(Node* view,
}
void WasmGraphBuilder::StringViewWtf8Encode(
uint32_t memory, wasm::StringRefWtf8Policy policy, Node* view,
uint32_t memory, unibrow::Utf8Variant variant, Node* view,
CheckForNull null_check, Node* addr, Node* pos, Node* bytes,
Node** next_pos, Node** bytes_written, wasm::WasmCodePosition position) {
if (null_check == kWithNullCheck) {
view = AssertNotNull(view, position);
}
Node* pair = gasm_->CallBuiltin(
Builtin::kWasmStringViewWtf8Encode, Operator::kNoDeopt, addr, pos, bytes,
view, gasm_->SmiConstant(memory), gasm_->SmiConstant(policy));
Node* pair =
gasm_->CallBuiltin(Builtin::kWasmStringViewWtf8Encode, Operator::kNoDeopt,
addr, pos, bytes, view, gasm_->SmiConstant(memory),
gasm_->SmiConstant(static_cast<int32_t>(variant)));
*next_pos = gasm_->Projection(0, pair);
*bytes_written = gasm_->Projection(1, pair);
}
......
......@@ -516,9 +516,9 @@ class WasmGraphBuilder {
void BrOnI31(Node* object, Node* rtt, WasmTypeCheckConfig config,
Node** match_control, Node** match_effect,
Node** no_match_control, Node** no_match_effect);
Node* StringNewWtf8(uint32_t memory, wasm::StringRefWtf8Policy policy,
Node* StringNewWtf8(uint32_t memory, unibrow::Utf8Variant variant,
Node* offset, Node* size);
Node* StringNewWtf8Array(wasm::StringRefWtf8Policy policy, Node* array,
Node* StringNewWtf8Array(unibrow::Utf8Variant variant, Node* array,
Node* start, Node* end);
Node* StringNewWtf16(uint32_t memory, Node* offset, Node* size);
Node* StringNewWtf16Array(Node* array, Node* start, Node* end);
......@@ -529,10 +529,10 @@ class WasmGraphBuilder {
wasm::WasmCodePosition position);
Node* StringMeasureWtf16(Node* string, CheckForNull null_check,
wasm::WasmCodePosition position);
Node* StringEncodeWtf8(uint32_t memory, wasm::StringRefWtf8Policy policy,
Node* StringEncodeWtf8(uint32_t memory, unibrow::Utf8Variant variant,
Node* string, CheckForNull null_check, Node* offset,
wasm::WasmCodePosition position);
Node* StringEncodeWtf8Array(wasm::StringRefWtf8Policy policy, Node* string,
Node* StringEncodeWtf8Array(unibrow::Utf8Variant variant, Node* string,
CheckForNull string_null_check, Node* array,
CheckForNull array_null_check, Node* start,
wasm::WasmCodePosition position);
......@@ -553,7 +553,7 @@ class WasmGraphBuilder {
wasm::WasmCodePosition position);
Node* StringViewWtf8Advance(Node* view, CheckForNull null_check, Node* pos,
Node* bytes, wasm::WasmCodePosition position);
void StringViewWtf8Encode(uint32_t memory, wasm::StringRefWtf8Policy policy,
void StringViewWtf8Encode(uint32_t memory, unibrow::Utf8Variant variant,
Node* view, CheckForNull null_check, Node* addr,
Node* pos, Node* bytes, Node** next_pos,
Node** bytes_written,
......
......@@ -854,20 +854,6 @@ RUNTIME_FUNCTION(Runtime_WasmCreateResumePromise) {
return *result;
}
namespace {
unibrow::Utf8Variant Utf8VariantFromWtf8Policy(
wasm::StringRefWtf8Policy policy) {
switch (policy) {
case wasm::kWtf8PolicyReject:
return unibrow::Utf8Variant::kUtf8;
case wasm::kWtf8PolicyAccept:
return unibrow::Utf8Variant::kWtf8;
case wasm::kWtf8PolicyReplace:
return unibrow::Utf8Variant::kLossyUtf8;
}
}
} // namespace
// Returns the new string if the operation succeeds. Otherwise throws an
// exception and returns an empty result.
RUNTIME_FUNCTION(Runtime_WasmStringNewWtf8) {
......@@ -876,16 +862,16 @@ RUNTIME_FUNCTION(Runtime_WasmStringNewWtf8) {
HandleScope scope(isolate);
WasmInstanceObject instance = WasmInstanceObject::cast(args[0]);
uint32_t memory = args.positive_smi_value_at(1);
uint32_t policy_value = args.positive_smi_value_at(2);
uint32_t utf8_variant_value = args.positive_smi_value_at(2);
uint32_t offset = NumberToUint32(args[3]);
uint32_t size = NumberToUint32(args[4]);
DCHECK_EQ(memory, 0);
USE(memory);
DCHECK(policy_value <= wasm::kLastWtf8Policy);
DCHECK(utf8_variant_value <=
static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
auto policy = static_cast<wasm::StringRefWtf8Policy>(policy_value);
auto utf8_variant = Utf8VariantFromWtf8Policy(policy);
auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
uint64_t mem_size = instance.memory_size();
if (!base::IsInBounds<uint64_t>(offset, size, mem_size)) {
......@@ -902,14 +888,14 @@ RUNTIME_FUNCTION(Runtime_WasmStringNewWtf8Array) {
ClearThreadInWasmScope flag_scope(isolate);
DCHECK_EQ(4, args.length());
HandleScope scope(isolate);
uint32_t policy_value = args.positive_smi_value_at(0);
uint32_t utf8_variant_value = args.positive_smi_value_at(0);
Handle<WasmArray> array(WasmArray::cast(args[1]), isolate);
uint32_t start = NumberToUint32(args[2]);
uint32_t end = NumberToUint32(args[3]);
DCHECK(policy_value <= wasm::kLastWtf8Policy);
auto policy = static_cast<wasm::StringRefWtf8Policy>(policy_value);
auto utf8_variant = Utf8VariantFromWtf8Policy(policy);
DCHECK(utf8_variant_value <=
static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromUtf8(
array, start, end, utf8_variant));
......@@ -1023,7 +1009,7 @@ bool HasUnpairedSurrogate(base::Vector<const base::uc16> wtf16) {
// TODO(12868): Consider unifying with api.cc:String::WriteUtf8.
template <typename T>
int EncodeWtf8(base::Vector<char> bytes, size_t offset,
base::Vector<const T> wtf16, wasm::StringRefWtf8Policy policy,
base::Vector<const T> wtf16, unibrow::Utf8Variant variant,
MessageTemplate* message, MessageTemplate out_of_bounds) {
// The first check is a quick estimate to decide whether the second check
// is worth the computation.
......@@ -1034,16 +1020,16 @@ int EncodeWtf8(base::Vector<char> bytes, size_t offset,
}
bool replace_invalid = false;
switch (policy) {
case wasm::kWtf8PolicyAccept:
switch (variant) {
case unibrow::Utf8Variant::kWtf8:
break;
case wasm::kWtf8PolicyReject:
case unibrow::Utf8Variant::kUtf8:
if (HasUnpairedSurrogate(wtf16)) {
*message = MessageTemplate::kWasmTrapStringIsolatedSurrogate;
return -1;
}
break;
case wasm::kWtf8PolicyReplace:
case unibrow::Utf8Variant::kLossyUtf8:
replace_invalid = true;
break;
default:
......@@ -1061,7 +1047,7 @@ int EncodeWtf8(base::Vector<char> bytes, size_t offset,
return static_cast<int>(dst - dst_start);
}
template <typename GetWritableBytes>
Object EncodeWtf8(Isolate* isolate, wasm::StringRefWtf8Policy policy,
Object EncodeWtf8(Isolate* isolate, unibrow::Utf8Variant variant,
Handle<String> string, GetWritableBytes get_writable_bytes,
size_t offset, MessageTemplate out_of_bounds_message) {
string = String::Flatten(isolate, string);
......@@ -1072,9 +1058,9 @@ Object EncodeWtf8(Isolate* isolate, wasm::StringRefWtf8Policy policy,
String::FlatContent content = string->GetFlatContent(no_gc);
base::Vector<char> dst = get_writable_bytes(no_gc);
written = content.IsOneByte()
? EncodeWtf8(dst, offset, content.ToOneByteVector(), policy,
? EncodeWtf8(dst, offset, content.ToOneByteVector(), variant,
&message, out_of_bounds_message)
: EncodeWtf8(dst, offset, content.ToUC16Vector(), policy,
: EncodeWtf8(dst, offset, content.ToUC16Vector(), variant,
&message, out_of_bounds_message);
}
if (written < 0) {
......@@ -1128,21 +1114,22 @@ RUNTIME_FUNCTION(Runtime_WasmStringEncodeWtf8) {
HandleScope scope(isolate);
WasmInstanceObject instance = WasmInstanceObject::cast(args[0]);
uint32_t memory = args.positive_smi_value_at(1);
uint32_t policy_value = args.positive_smi_value_at(2);
uint32_t utf8_variant_value = args.positive_smi_value_at(2);
Handle<String> string(String::cast(args[3]), isolate);
uint32_t offset = NumberToUint32(args[4]);
DCHECK_EQ(memory, 0);
USE(memory);
DCHECK(policy_value <= wasm::kLastWtf8Policy);
DCHECK(utf8_variant_value <=
static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
char* memory_start = reinterpret_cast<char*>(instance.memory_start());
auto policy = static_cast<wasm::StringRefWtf8Policy>(policy_value);
auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
auto get_writable_bytes =
[&](const DisallowGarbageCollection&) -> base::Vector<char> {
return {memory_start, instance.memory_size()};
};
return EncodeWtf8(isolate, policy, string, get_writable_bytes, offset,
return EncodeWtf8(isolate, utf8_variant, string, get_writable_bytes, offset,
MessageTemplate::kWasmTrapMemOutOfBounds);
}
......@@ -1150,18 +1137,19 @@ RUNTIME_FUNCTION(Runtime_WasmStringEncodeWtf8Array) {
ClearThreadInWasmScope flag_scope(isolate);
DCHECK_EQ(4, args.length());
HandleScope scope(isolate);
uint32_t policy_value = args.positive_smi_value_at(0);
uint32_t utf8_variant_value = args.positive_smi_value_at(0);
Handle<String> string(String::cast(args[1]), isolate);
Handle<WasmArray> array(WasmArray::cast(args[2]), isolate);
uint32_t start = NumberToUint32(args[3]);
DCHECK(policy_value <= wasm::kLastWtf8Policy);
auto policy = static_cast<wasm::StringRefWtf8Policy>(policy_value);
DCHECK(utf8_variant_value <=
static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
auto get_writable_bytes =
[&](const DisallowGarbageCollection&) -> base::Vector<char> {
return {reinterpret_cast<char*>(array->ElementAddress(0)), array->length()};
};
return EncodeWtf8(isolate, policy, string, get_writable_bytes, start,
return EncodeWtf8(isolate, utf8_variant, string, get_writable_bytes, start,
MessageTemplate::kWasmTrapArrayOutOfBounds);
}
......@@ -1215,13 +1203,13 @@ RUNTIME_FUNCTION(Runtime_WasmStringAsWtf8) {
int wtf8_length = MeasureWtf8(isolate, string);
Handle<ByteArray> array = isolate->factory()->NewByteArray(wtf8_length);
wasm::StringRefWtf8Policy policy = wasm::kWtf8PolicyAccept;
auto utf8_variant = unibrow::Utf8Variant::kWtf8;
auto get_writable_bytes =
[&](const DisallowGarbageCollection&) -> base::Vector<char> {
return {reinterpret_cast<char*>(array->GetDataStartAddress()),
static_cast<size_t>(wtf8_length)};
};
EncodeWtf8(isolate, policy, string, get_writable_bytes, 0,
EncodeWtf8(isolate, utf8_variant, string, get_writable_bytes, 0,
MessageTemplate::kWasmTrapArrayOutOfBounds);
return *array;
}
......@@ -1231,17 +1219,18 @@ RUNTIME_FUNCTION(Runtime_WasmStringViewWtf8Encode) {
DCHECK_EQ(6, args.length());
HandleScope scope(isolate);
WasmInstanceObject instance = WasmInstanceObject::cast(args[0]);
uint32_t policy_value = args.positive_smi_value_at(1);
uint32_t utf8_variant_value = args.positive_smi_value_at(1);
Handle<ByteArray> array(ByteArray::cast(args[2]), isolate);
uint32_t addr = NumberToUint32(args[3]);
uint32_t start = NumberToUint32(args[4]);
uint32_t end = NumberToUint32(args[5]);
DCHECK(policy_value <= wasm::kLastWtf8Policy);
DCHECK(utf8_variant_value <=
static_cast<uint32_t>(unibrow::Utf8Variant::kLastUtf8Variant));
DCHECK_LE(start, end);
DCHECK(base::IsInBounds<size_t>(start, end - start, array->length()));
auto policy = static_cast<wasm::StringRefWtf8Policy>(policy_value);
auto utf8_variant = static_cast<unibrow::Utf8Variant>(utf8_variant_value);
size_t length = end - start;
if (!base::IsInBounds<size_t>(addr, length, instance.memory_size())) {
......@@ -1254,9 +1243,9 @@ RUNTIME_FUNCTION(Runtime_WasmStringViewWtf8Encode) {
byte* dst = memory_start + addr;
std::vector<size_t> surrogates;
if (policy != wasm::kWtf8PolicyAccept) {
if (utf8_variant != unibrow::Utf8Variant::kWtf8) {
unibrow::Wtf8::ScanForSurrogates({src, length}, &surrogates);
if (policy == wasm::kWtf8PolicyReject && !surrogates.empty()) {
if (utf8_variant == unibrow::Utf8Variant::kUtf8 && !surrogates.empty()) {
return ThrowWasmError(isolate,
MessageTemplate::kWasmTrapStringIsolatedSurrogate);
}
......@@ -1266,7 +1255,7 @@ RUNTIME_FUNCTION(Runtime_WasmStringViewWtf8Encode) {
for (size_t surrogate : surrogates) {
DCHECK_LT(surrogate, length);
DCHECK_EQ(policy, wasm::kWtf8PolicyReplace);
DCHECK_EQ(utf8_variant, unibrow::Utf8Variant::kLossyUtf8);
unibrow::Utf8::Encode(reinterpret_cast<char*>(dst + surrogate),
unibrow::Utf8::kBadChar, 0, false);
}
......
......@@ -154,16 +154,17 @@ class Latin1 {
};
enum class Utf8Variant : uint8_t {
kLossyUtf8, // Lossy UTF-8: Any byte sequence can be decoded without
// error, replacing invalid UTF-8 with the replacement
// character (U+FFFD). Any sequence of codepoints can be
// encoded without error, replacing surrogates with U+FFFD.
#if V8_ENABLE_WEBASSEMBLY
kUtf8, // UTF-8. Decoding an invalid byte sequence or encoding a
// surrogate codepoint signals an error.
kWtf8, // WTF-8: like UTF-8, but allows isolated (but not paired)
// surrogate codepoints to be encoded and decoded.
#endif
kLossyUtf8, // Lossy UTF-8: Any byte sequence can be decoded without
// error, replacing invalid UTF-8 with the replacement
// character (U+FFFD). Any sequence of codepoints can be
// encoded without error, replacing surrogates with U+FFFD.
kLastUtf8Variant = kLossyUtf8
};
class V8_EXPORT_PRIVATE Utf8 {
......
......@@ -6262,19 +6262,20 @@ class LiftoffCompiler {
}
void StringNewWtf8(FullDecoder* decoder,
const EncodeWtf8Immediate<validate>& imm,
const Value& offset, const Value& size, Value* result) {
const MemoryIndexImmediate<validate>& imm,
const unibrow::Utf8Variant variant, const Value& offset,
const Value& size, Value* result) {
LiftoffRegList pinned;
LiftoffRegister memory_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
LoadSmi(memory_reg, imm.memory.index);
LoadSmi(memory_reg, imm.index);
LiftoffAssembler::VarState memory_var(kSmiKind, memory_reg, 0);
LiftoffRegister policy_reg =
LiftoffRegister variant_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
LoadSmi(policy_reg, static_cast<int32_t>(imm.policy.value));
LiftoffAssembler::VarState policy_var(kSmiKind, policy_reg, 0);
LoadSmi(variant_reg, static_cast<int32_t>(variant));
LiftoffAssembler::VarState variant_var(kSmiKind, variant_reg, 0);
CallRuntimeStub(
WasmCode::kWasmStringNewWtf8,
......@@ -6283,7 +6284,7 @@ class LiftoffCompiler {
__ cache_state()->stack_state.end()[-2], // offset
__ cache_state()->stack_state.end()[-1], // size
memory_var,
policy_var,
variant_var,
},
decoder->position());
__ cache_state()->stack_state.pop_back(2);
......@@ -6294,7 +6295,7 @@ class LiftoffCompiler {
}
void StringNewWtf8Array(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const unibrow::Utf8Variant variant,
const Value& array, const Value& start,
const Value& end, Value* result) {
LiftoffRegList pinned;
......@@ -6304,10 +6305,10 @@ class LiftoffCompiler {
MaybeEmitNullCheck(decoder, array_reg.gp(), pinned, array.type);
LiftoffAssembler::VarState array_var(kRef, array_reg, 0);
LiftoffRegister policy_reg =
LiftoffRegister variant_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
LoadSmi(policy_reg, static_cast<int32_t>(imm.value));
LiftoffAssembler::VarState policy_var(kSmiKind, policy_reg, 0);
LoadSmi(variant_reg, static_cast<int32_t>(variant));
LiftoffAssembler::VarState variant_var(kSmiKind, variant_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringNewWtf8Array,
MakeSig::Returns(kRef).Params(kI32, kI32, kRef, kSmiKind),
......@@ -6315,7 +6316,7 @@ class LiftoffCompiler {
__ cache_state()->stack_state.end()[-2], // start
__ cache_state()->stack_state.end()[-1], // end
array_var,
policy_var,
variant_var,
},
decoder->position());
__ cache_state()->stack_state.pop_back(3);
......@@ -6395,20 +6396,20 @@ class LiftoffCompiler {
}
void StringMeasureWtf8(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const Value& str, Value* result) {
const unibrow::Utf8Variant variant, const Value& str,
Value* result) {
LiftoffRegList pinned;
LiftoffRegister string_reg = pinned.set(__ PopToRegister(pinned));
MaybeEmitNullCheck(decoder, string_reg.gp(), pinned, str.type);
LiftoffAssembler::VarState string_var(kRef, string_reg, 0);
WasmCode::RuntimeStubId stub_id;
switch (imm.value) {
case kWtf8PolicyReject:
switch (variant) {
case unibrow::Utf8Variant::kUtf8:
stub_id = WasmCode::kWasmStringMeasureUtf8;
break;
case kWtf8PolicyAccept:
case kWtf8PolicyReplace:
case unibrow::Utf8Variant::kLossyUtf8:
case unibrow::Utf8Variant::kWtf8:
stub_id = WasmCode::kWasmStringMeasureWtf8;
break;
}
......@@ -6436,8 +6437,9 @@ class LiftoffCompiler {
}
void StringEncodeWtf8(FullDecoder* decoder,
const EncodeWtf8Immediate<validate>& imm,
const Value& str, const Value& offset, Value* result) {
const MemoryIndexImmediate<validate>& imm,
const unibrow::Utf8Variant variant, const Value& str,
const Value& offset, Value* result) {
LiftoffRegList pinned;
LiftoffAssembler::VarState& offset_var =
......@@ -6450,13 +6452,13 @@ class LiftoffCompiler {
LiftoffRegister memory_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
LoadSmi(memory_reg, imm.memory.index);
LoadSmi(memory_reg, imm.index);
LiftoffAssembler::VarState memory_var(kSmiKind, memory_reg, 0);
LiftoffRegister policy_reg =
LiftoffRegister variant_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
LoadSmi(policy_reg, static_cast<int32_t>(imm.policy.value));
LiftoffAssembler::VarState policy_var(kSmiKind, policy_reg, 0);
LoadSmi(variant_reg, static_cast<int32_t>(variant));
LiftoffAssembler::VarState variant_var(kSmiKind, variant_reg, 0);
CallRuntimeStub(
WasmCode::kWasmStringEncodeWtf8,
......@@ -6465,7 +6467,7 @@ class LiftoffCompiler {
string_var,
offset_var,
memory_var,
policy_var,
variant_var,
},
decoder->position());
__ DropValues(2);
......@@ -6476,7 +6478,7 @@ class LiftoffCompiler {
}
void StringEncodeWtf8Array(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const unibrow::Utf8Variant variant,
const Value& str, const Value& array,
const Value& start, Value* result) {
LiftoffRegList pinned;
......@@ -6494,10 +6496,10 @@ class LiftoffCompiler {
LiftoffAssembler::VarState& start_var =
__ cache_state()->stack_state.end()[-1];
LiftoffRegister policy_reg =
LiftoffRegister variant_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
LoadSmi(policy_reg, static_cast<int32_t>(imm.value));
LiftoffAssembler::VarState policy_var(kSmiKind, policy_reg, 0);
LoadSmi(variant_reg, static_cast<int32_t>(variant));
LiftoffAssembler::VarState variant_var(kSmiKind, variant_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringEncodeWtf8Array,
MakeSig::Returns(kI32).Params(kRef, kRef, kI32, kSmiKind),
......@@ -6505,7 +6507,7 @@ class LiftoffCompiler {
string_var,
array_var,
start_var,
policy_var,
variant_var,
},
decoder->position());
__ DropValues(3);
......@@ -6737,7 +6739,8 @@ class LiftoffCompiler {
}
void StringViewWtf8Encode(FullDecoder* decoder,
const EncodeWtf8Immediate<validate>& imm,
const MemoryIndexImmediate<validate>& imm,
const unibrow::Utf8Variant variant,
const Value& view, const Value& addr,
const Value& pos, const Value& bytes,
Value* next_pos, Value* bytes_written) {
......@@ -6757,13 +6760,13 @@ class LiftoffCompiler {
LiftoffRegister memory_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
LoadSmi(memory_reg, imm.memory.index);
LoadSmi(memory_reg, imm.index);
LiftoffAssembler::VarState memory_var(kSmiKind, memory_reg, 0);
LiftoffRegister policy_reg =
LiftoffRegister variant_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
LoadSmi(policy_reg, static_cast<int32_t>(imm.policy.value));
LiftoffAssembler::VarState policy_var(kSmiKind, policy_reg, 0);
LoadSmi(variant_reg, static_cast<int32_t>(variant));
LiftoffAssembler::VarState variant_var(kSmiKind, variant_reg, 0);
CallRuntimeStub(WasmCode::kWasmStringViewWtf8Encode,
MakeSig::Returns(kI32, kI32)
......@@ -6774,7 +6777,7 @@ class LiftoffCompiler {
bytes_var,
view_var,
memory_var,
policy_var,
variant_var,
},
decoder->position());
__ DropValues(4);
......
This diff is collapsed.
......@@ -1371,18 +1371,18 @@ class WasmGraphBuildingInterface {
}
void StringNewWtf8(FullDecoder* decoder,
const EncodeWtf8Immediate<validate>& imm,
const Value& offset, const Value& size, Value* result) {
SetAndTypeNode(result,
builder_->StringNewWtf8(imm.memory.index, imm.policy.value,
offset.node, size.node));
const MemoryIndexImmediate<validate>& memory,
const unibrow::Utf8Variant variant, const Value& offset,
const Value& size, Value* result) {
SetAndTypeNode(result, builder_->StringNewWtf8(memory.index, variant,
offset.node, size.node));
}
void StringNewWtf8Array(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const unibrow::Utf8Variant variant,
const Value& array, const Value& start,
const Value& end, Value* result) {
SetAndTypeNode(result, builder_->StringNewWtf8Array(imm.value, array.node,
SetAndTypeNode(result, builder_->StringNewWtf8Array(variant, array.node,
start.node, end.node));
}
......@@ -1406,15 +1406,15 @@ class WasmGraphBuildingInterface {
}
void StringMeasureWtf8(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const Value& str, Value* result) {
switch (imm.value) {
case kWtf8PolicyReject:
const unibrow::Utf8Variant variant, const Value& str,
Value* result) {
switch (variant) {
case unibrow::Utf8Variant::kUtf8:
result->node = builder_->StringMeasureUtf8(
str.node, NullCheckFor(str.type), decoder->position());
break;
case kWtf8PolicyAccept:
case kWtf8PolicyReplace:
case unibrow::Utf8Variant::kLossyUtf8:
case unibrow::Utf8Variant::kWtf8:
result->node = builder_->StringMeasureWtf8(
str.node, NullCheckFor(str.type), decoder->position());
break;
......@@ -1428,19 +1428,20 @@ class WasmGraphBuildingInterface {
}
void StringEncodeWtf8(FullDecoder* decoder,
const EncodeWtf8Immediate<validate>& imm,
const Value& str, const Value& offset, Value* result) {
result->node = builder_->StringEncodeWtf8(
imm.memory.index, imm.policy.value, str.node, NullCheckFor(str.type),
offset.node, decoder->position());
const MemoryIndexImmediate<validate>& memory,
const unibrow::Utf8Variant variant, const Value& str,
const Value& offset, Value* result) {
result->node = builder_->StringEncodeWtf8(memory.index, variant, str.node,
NullCheckFor(str.type),
offset.node, decoder->position());
}
void StringEncodeWtf8Array(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const unibrow::Utf8Variant variant,
const Value& str, const Value& array,
const Value& start, Value* result) {
result->node = builder_->StringEncodeWtf8Array(
imm.value, str.node, NullCheckFor(str.type), array.node,
variant, str.node, NullCheckFor(str.type), array.node,
NullCheckFor(array.type), start.node, decoder->position());
}
......@@ -1495,14 +1496,15 @@ class WasmGraphBuildingInterface {
}
void StringViewWtf8Encode(FullDecoder* decoder,
const EncodeWtf8Immediate<validate>& imm,
const MemoryIndexImmediate<validate>& memory,
const unibrow::Utf8Variant variant,
const Value& view, const Value& addr,
const Value& pos, const Value& bytes,
Value* next_pos, Value* bytes_written) {
builder_->StringViewWtf8Encode(
imm.memory.index, imm.policy.value, view.node, NullCheckFor(view.type),
addr.node, pos.node, bytes.node, &next_pos->node, &bytes_written->node,
decoder->position());
builder_->StringViewWtf8Encode(memory.index, variant, view.node,
NullCheckFor(view.type), addr.node, pos.node,
bytes.node, &next_pos->node,
&bytes_written->node, decoder->position());
}
void StringViewWtf8Slice(FullDecoder* decoder, const Value& view,
......
......@@ -147,16 +147,6 @@ enum NameSectionKindCode : uint8_t {
kTagCode = 11,
};
// What to do when treating a stringref as WTF-8 and we see an isolated
// surrogate.
enum StringRefWtf8Policy : uint8_t {
kWtf8PolicyReject = 0, // Strict UTF-8; no isolated surrogates allowed.
kWtf8PolicyAccept = 1, // Follow WTF-8 encoding of isolates surrogates.
kWtf8PolicyReplace = 2, // Replace isolated surrogates and decoding errors
// with U+FFFD.
kLastWtf8Policy = kWtf8PolicyReplace
};
constexpr size_t kWasmPageSize = 0x10000;
constexpr uint32_t kWasmPageSizeLog2 = 16;
static_assert(kWasmPageSize == size_t{1} << kWasmPageSizeLog2, "consistency");
......
......@@ -375,13 +375,6 @@ class ImmediatesPrinter {
out_ << " " << imm.index; // --
}
void Wtf8Policy(Wtf8PolicyImmediate<validate>& imm) {
out_ << (imm.value == kWtf8PolicyReject ? " reject"
: imm.value == kWtf8PolicyAccept ? " accept"
: imm.value == kWtf8PolicyReplace ? " replace"
: " unknown-policy");
}
void TagIndex(TagIndexImmediate<validate>& imm) {
out_ << " ";
names()->PrintTagName(out_, imm.index);
......
......@@ -726,20 +726,28 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
V(BrOnNonArray, 0xfb67, _, "br_on_non_array") \
V(ExternInternalize, 0xfb70, _, "extern.internalize") \
V(ExternExternalize, 0xfb71, _, "extern.externalize") \
V(StringNewWtf8, 0xfb80, _, "string.new_wtf8") \
V(StringNewUtf8, 0xfb80, _, "string.new_utf8") \
V(StringNewWtf16, 0xfb81, _, "string.new_wtf16") \
V(StringConst, 0xfb82, _, "string.const") \
V(StringMeasureUtf8, 0xfb83, _, "string.measure_utf8") \
V(StringMeasureWtf8, 0xfb84, _, "string.measure_wtf8") \
V(StringMeasureWtf16, 0xfb85, _, "string.measure_wtf16") \
V(StringEncodeWtf8, 0xfb86, _, "string.encode_wtf8") \
V(StringEncodeUtf8, 0xfb86, _, "string.encode_utf8") \
V(StringEncodeWtf16, 0xfb87, _, "string.encode_wtf16") \
V(StringConcat, 0xfb88, _, "string.concat") \
V(StringEq, 0xfb89, _, "string.eq") \
V(StringIsUSVSequence, 0xfb8a, _, "string.is_usv_sequence") \
V(StringNewLossyUtf8, 0xfb8b, _, "string.new_lossy_utf8") \
V(StringNewWtf8, 0xfb8c, _, "string.new_wtf8") \
V(StringEncodeLossyUtf8, 0xfb8d, _, "string.encode_lossy_utf8") \
V(StringEncodeWtf8, 0xfb8e, _, "string.encode_wtf8") \
V(StringAsWtf8, 0xfb90, _, "string.as_wtf8") \
V(StringViewWtf8Advance, 0xfb91, _, "stringview_wtf8.advance") \
V(StringViewWtf8Encode, 0xfb92, _, "stringview_wtf8.encode") \
V(StringViewWtf8EncodeUtf8, 0xfb92, _, "stringview_wtf8.encode_utf8") \
V(StringViewWtf8Slice, 0xfb93, _, "stringview_wtf8.slice") \
V(StringViewWtf8EncodeLossyUtf8, 0xfb94, _, \
"stringview_wtf8.encode_lossy_utf8") \
V(StringViewWtf8EncodeWtf8, 0xfb95, _, "stringview_wtf8.encode_wtf8") \
V(StringAsWtf16, 0xfb98, _, "string.as_wtf16") \
V(StringViewWtf16Length, 0xfb99, _, "stringview_wtf16.length") \
V(StringViewWtf16GetCodeUnit, 0xfb9a, _, "stringview_wtf16.get_codeunit") \
......@@ -750,10 +758,14 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
V(StringViewIterAdvance, 0xfba2, _, "stringview_iter.advance") \
V(StringViewIterRewind, 0xfba3, _, "stringview_iter.rewind") \
V(StringViewIterSlice, 0xfba4, _, "stringview_iter.slice") \
V(StringNewWtf8Array, 0xfbb0, _, "string.new_wtf8_array") \
V(StringNewUtf8Array, 0xfbb0, _, "string.new_utf8_array") \
V(StringNewWtf16Array, 0xfbb1, _, "string.new_wtf16_array") \
V(StringEncodeWtf8Array, 0xfbb2, _, "string.encode_wtf8_array") \
V(StringEncodeWtf16Array, 0xfbb3, _, "string.encode_wtf16_array")
V(StringEncodeUtf8Array, 0xfbb2, _, "string.encode_utf8_array") \
V(StringEncodeWtf16Array, 0xfbb3, _, "string.encode_wtf16_array") \
V(StringNewLossyUtf8Array, 0xfbb4, _, "string.new_lossy_utf8_array") \
V(StringNewWtf8Array, 0xfbb5, _, "string.new_wtf8_array") \
V(StringEncodeLossyUtf8Array, 0xfbb6, _, "string.encode_lossy_utf8_array") \
V(StringEncodeWtf8Array, 0xfbb7, _, "string.encode_wtf8_array")
// All opcodes.
#define FOREACH_OPCODE(V) \
......
......@@ -114,15 +114,16 @@ function makeWtf8TestDataSegment() {
kGCPrefix, kExprArrayNewData, i8_array, data_index
]).index;
for (let [policy, name] of [[kWtf8PolicyAccept, "new_wtf8"],
[kWtf8PolicyReject, "new_utf8"],
[kWtf8PolicyReplace, "new_utf8_sloppy"]]) {
for (let [instr, name] of
[[kExprStringNewWtf8Array, "new_wtf8"],
[kExprStringNewUtf8Array, "new_utf8"],
[kExprStringNewLossyUtf8Array, "new_utf8_sloppy"]]) {
builder.addFunction(name, kSig_w_ii)
.exportFunc()
.addBody([
kExprCallFunction, make_i8_array,
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8Array), policy
...GCInstr(instr)
]);
}
......@@ -133,7 +134,7 @@ function makeWtf8TestDataSegment() {
...wasmI32Const("ascii".length),
kGCPrefix, kExprArrayNewData, i8_array, ascii_data_index,
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8Array), kWtf8PolicyAccept
...GCInstr(kExprStringNewWtf8Array)
]);
let instance = builder.instantiate();
......@@ -268,7 +269,9 @@ function makeWtf16TestDataSegment() {
let kSig_w_wii =
makeSig([kWasmStringRef, kWasmI32, kWasmI32],
[kWasmStringRef]);
for (let [policy, name] of ["utf8", "wtf8", "replace"].entries()) {
for (let [instr, name] of [[kExprStringEncodeUtf8Array, "utf8"],
[kExprStringEncodeWtf8Array, "wtf8"],
[kExprStringEncodeLossyUtf8Array, "replace"]]) {
// Allocate an array that's exactly the expected size, and encode
// into it. Then decode it.
// (str, length, offset=0) -> str
......@@ -286,14 +289,14 @@ function makeWtf16TestDataSegment() {
kExprLocalGet, 0,
kExprLocalGet, 3,
kExprLocalGet, 2,
...GCInstr(kExprStringEncodeWtf8Array), policy,
...GCInstr(instr),
kExprLocalSet, 4,
// Read buffer.
kExprLocalGet, 3,
kExprLocalGet, 2,
kExprLocalGet, 2, kExprLocalGet, 4, kExprI32Add,
...GCInstr(kExprStringNewWtf8Array), kWtf8PolicyAccept,
...GCInstr(kExprStringNewWtf8Array)
]);
}
......@@ -303,17 +306,17 @@ function makeWtf16TestDataSegment() {
kExprRefNull, kStringRefCode,
kExprI32Const, 0, kGCPrefix, kExprArrayNewDefault, i8_array,
kExprI32Const, 0,
...GCInstr(kExprStringEncodeWtf8Array), 0,
...GCInstr(kExprStringEncodeWtf8Array)
]);
builder.addFunction("encode_null_array", kSig_i_v)
.exportFunc()
.addBody([
kExprI32Const, 0, kGCPrefix, kExprArrayNewDefault, i8_array,
kExprI32Const, 0, kExprI32Const, 0,
...GCInstr(kExprStringNewWtf8Array), kWtf8PolicyAccept,
...GCInstr(kExprStringNewWtf8Array),
kExprRefNull, i8_array,
kExprI32Const, 0,
...GCInstr(kExprStringEncodeWtf8Array), kWtf8PolicyAccept,
...GCInstr(kExprStringEncodeWtf8Array)
]);
let instance = builder.instantiate();
......
......@@ -162,21 +162,21 @@ function makeWtf8TestDataSegment() {
.exportFunc()
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8), 0, kWtf8PolicyReject
...GCInstr(kExprStringNewUtf8), 0
]);
builder.addFunction("string_new_wtf8", kSig_w_ii)
.exportFunc()
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8), 0, kWtf8PolicyAccept
...GCInstr(kExprStringNewWtf8), 0
]);
builder.addFunction("string_new_utf8_sloppy", kSig_w_ii)
.exportFunc()
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8), 0, kWtf8PolicyReplace
...GCInstr(kExprStringNewLossyUtf8), 0
]);
let instance = builder.instantiate();
......@@ -282,50 +282,34 @@ function makeWtf16TestDataSegment() {
.exportFunc()
.addBody([
kExprLocalGet, 0,
...GCInstr(kExprStringMeasureWtf8), 0
...GCInstr(kExprStringMeasureUtf8)
]);
builder.addFunction("string_measure_wtf8", kSig_i_w)
.exportFunc()
.addBody([
kExprLocalGet, 0,
...GCInstr(kExprStringMeasureWtf8), 1
]);
builder.addFunction("string_measure_wtf8_replace", kSig_i_w)
.exportFunc()
.addBody([
kExprLocalGet, 0,
...GCInstr(kExprStringMeasureWtf8), 2
...GCInstr(kExprStringMeasureWtf8)
]);
builder.addFunction("string_measure_utf8_null", kSig_i_v)
.exportFunc()
.addBody([
kExprRefNull, kStringRefCode,
...GCInstr(kExprStringMeasureWtf8), 0
...GCInstr(kExprStringMeasureUtf8)
]);
builder.addFunction("string_measure_wtf8_null", kSig_i_v)
.exportFunc()
.addBody([
kExprRefNull, kStringRefCode,
...GCInstr(kExprStringMeasureWtf8), 1
]);
builder.addFunction("string_measure_wtf8_replace_null", kSig_i_v)
.exportFunc()
.addBody([
kExprRefNull, kStringRefCode,
...GCInstr(kExprStringMeasureWtf8), 2
...GCInstr(kExprStringMeasureWtf8)
]);
let instance = builder.instantiate();
for (let str of interestingStrings) {
let wtf8 = encodeWtf8(str);
assertEquals(wtf8.length, instance.exports.string_measure_wtf8(str));
assertEquals(wtf8.length,
instance.exports.string_measure_wtf8_replace(str));
if (HasIsolatedSurrogate(str)) {
assertEquals(-1, instance.exports.string_measure_utf8(str));
} else {
......@@ -337,8 +321,6 @@ function makeWtf16TestDataSegment() {
WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.string_measure_wtf8_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer");
assertThrows(() => instance.exports.string_measure_wtf8_replace_null(),
WebAssembly.RuntimeError, "dereferencing a null pointer");
})();
(function TestStringMeasureWtf16() {
......@@ -372,13 +354,15 @@ function makeWtf16TestDataSegment() {
builder.addMemory(1, undefined, true /* exported */, false);
for (let [policy, name] of ["utf8", "wtf8", "replace"].entries()) {
for (let [instr, name] of [[kExprStringEncodeUtf8, "utf8"],
[kExprStringEncodeWtf8, "wtf8"],
[kExprStringEncodeLossyUtf8, "replace"]]) {
builder.addFunction("encode_" + name, kSig_i_wi)
.exportFunc()
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
...GCInstr(kExprStringEncodeWtf8), 0, policy,
...GCInstr(instr), 0,
]);
}
......@@ -860,9 +844,10 @@ function makeWtf16TestDataSegment() {
...GCInstr(kExprStringViewWtf8Advance)
]);
for (let [name, policy] of Object.entries({utf8: kWtf8PolicyReject,
wtf8: kWtf8PolicyAccept,
replace: kWtf8PolicyReplace})) {
for (let [instr, name] of
[[kExprStringViewWtf8EncodeUtf8, "utf8"],
[kExprStringViewWtf8EncodeWtf8, "wtf8"],
[kExprStringViewWtf8EncodeLossyUtf8, "replace"]]) {
builder.addFunction(`encode_${name}`, kSig_ii_wiii)
.exportFunc()
.addBody([
......@@ -871,7 +856,7 @@ function makeWtf16TestDataSegment() {
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 3,
...GCInstr(kExprStringViewWtf8Encode), 0, policy
...GCInstr(instr), 0
]);
}
builder.addFunction("encode_null", kSig_v_v)
......@@ -881,7 +866,7 @@ function makeWtf16TestDataSegment() {
kExprI32Const, 0,
kExprI32Const, 0,
kExprI32Const, 0,
...GCInstr(kExprStringViewWtf8Encode), 0, kWtf8PolicyAccept,
...GCInstr(kExprStringViewWtf8EncodeWtf8), 0,
kExprDrop,
kExprDrop
]);
......
......@@ -72,22 +72,20 @@ let kSig_w_zi = makeSig([kWasmStringViewIter, kWasmI32],
builder.addMemory(0, undefined, false, false);
builder.addFunction("string.new_wtf8/reject", kSig_w_ii)
builder.addFunction("string.new_utf8", kSig_w_ii)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8), 0, kWtf8PolicyReject
...GCInstr(kExprStringNewUtf8), 0
]);
builder.addFunction("string.new_wtf8/accept", kSig_w_ii)
builder.addFunction("string.new_lossy_utf8", kSig_w_ii)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8), 0, kWtf8PolicyAccept
...GCInstr(kExprStringNewLossyUtf8), 0
]);
builder.addFunction("string.new_wtf8/replace", kSig_w_ii)
builder.addFunction("string.new_wtf8", kSig_w_ii)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8), 0, kWtf8PolicyReplace
...GCInstr(kExprStringNewWtf8), 0
]);
builder.addFunction("string.new_wtf16", kSig_w_ii)
......@@ -102,22 +100,15 @@ let kSig_w_zi = makeSig([kWasmStringViewIter, kWasmI32],
...GCInstr(kExprStringConst), 0
]);
builder.addFunction("string.measure_wtf8/utf-8", kSig_i_w)
.addBody([
kExprLocalGet, 0,
...GCInstr(kExprStringMeasureWtf8), kWtf8PolicyReject
]);
builder.addFunction("string.measure_wtf8/wtf-8", kSig_i_w)
builder.addFunction("string.measure_utf8", kSig_i_w)
.addBody([
kExprLocalGet, 0,
...GCInstr(kExprStringMeasureWtf8), kWtf8PolicyAccept
...GCInstr(kExprStringMeasureUtf8)
]);
builder.addFunction("string.measure_wtf8/replace", kSig_i_w)
builder.addFunction("string.measure_wtf8", kSig_i_w)
.addBody([
kExprLocalGet, 0,
...GCInstr(kExprStringMeasureWtf8), kWtf8PolicyReplace
...GCInstr(kExprStringMeasureWtf8)
]);
builder.addFunction("string.measure_wtf16", kSig_i_w)
......@@ -126,20 +117,20 @@ let kSig_w_zi = makeSig([kWasmStringViewIter, kWasmI32],
...GCInstr(kExprStringMeasureWtf16)
]);
builder.addFunction("string.encode_wtf8/utf-8", kSig_i_wi)
builder.addFunction("string.encode_utf8", kSig_i_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringEncodeWtf8), 0, kWtf8PolicyAccept
...GCInstr(kExprStringEncodeUtf8), 0
]);
builder.addFunction("string.encode_wtf8/wtf-8", kSig_i_wi)
builder.addFunction("string.encode_lossy_utf8", kSig_i_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringEncodeWtf8), 0, kWtf8PolicyReject
...GCInstr(kExprStringEncodeLossyUtf8), 0
]);
builder.addFunction("string.encode_wtf8/replace", kSig_i_wi)
builder.addFunction("string.encode_wtf8", kSig_i_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringEncodeWtf8), 0, kWtf8PolicyReplace
...GCInstr(kExprStringEncodeWtf8), 0
]);
builder.addFunction("string.encode_wtf16", kSig_i_wi)
......@@ -172,22 +163,20 @@ let kSig_w_zi = makeSig([kWasmStringViewIter, kWasmI32],
...GCInstr(kExprStringViewWtf8Advance)
]);
builder.addFunction("stringview_wtf8.encode/utf-8", kSig_ii_xiii)
builder.addFunction("stringview_wtf8.encode_utf8", kSig_ii_xiii)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2, kExprLocalGet, 3,
...GCInstr(kExprStringViewWtf8Encode), 0, 0
...GCInstr(kExprStringViewWtf8EncodeUtf8), 0
]);
builder.addFunction("stringview_wtf8.encode/wtf-8", kSig_ii_xiii)
builder.addFunction("stringview_wtf8.encode_lossy_utf8", kSig_ii_xiii)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2, kExprLocalGet, 3,
...GCInstr(kExprStringViewWtf8Encode), 0, 1
...GCInstr(kExprStringViewWtf8EncodeLossyUtf8), 0
]);
builder.addFunction("stringview_wtf8.encode/replace", kSig_ii_xiii)
builder.addFunction("stringview_wtf8.encode_wtf8", kSig_ii_xiii)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2, kExprLocalGet, 3,
...GCInstr(kExprStringViewWtf8Encode), 0, 2
...GCInstr(kExprStringViewWtf8EncodeWtf8), 0
]);
builder.addFunction("stringview_wtf8.slice", kSig_w_xii)
......@@ -259,28 +248,26 @@ let kSig_w_zi = makeSig([kWasmStringViewIter, kWasmI32],
let i8_array = builder.addArray(kWasmI8, true);
let i16_array = builder.addArray(kWasmI16, true);
builder.addFunction("string.new_wtf8_array/accept", kSig_w_v)
builder.addFunction("string.new_utf8_array", kSig_w_v)
.addBody([
kExprRefNull, i8_array,
kExprI32Const, 0,
kExprI32Const, 0,
...GCInstr(kExprStringNewWtf8Array), kWtf8PolicyAccept
...GCInstr(kExprStringNewWtf8Array)
]);
builder.addFunction("string.new_wtf8_array/reject", kSig_w_v)
builder.addFunction("string.new_lossy_utf8_array", kSig_w_v)
.addBody([
kExprRefNull, i8_array,
kExprI32Const, 0,
kExprI32Const, 0,
...GCInstr(kExprStringNewWtf8Array), kWtf8PolicyReject
...GCInstr(kExprStringNewLossyUtf8Array)
]);
builder.addFunction("string.new_wtf8_array/replace", kSig_w_v)
builder.addFunction("string.new_wtf8_array", kSig_w_v)
.addBody([
kExprRefNull, i8_array,
kExprI32Const, 0,
kExprI32Const, 0,
...GCInstr(kExprStringNewWtf8Array), kWtf8PolicyReplace
...GCInstr(kExprStringNewWtf8Array)
]);
builder.addFunction("string.new_wtf16_array", kSig_w_v)
......@@ -291,28 +278,26 @@ let kSig_w_zi = makeSig([kWasmStringViewIter, kWasmI32],
...GCInstr(kExprStringNewWtf16Array)
]);
builder.addFunction("string.encode_wtf8_array/accept", kSig_i_v)
builder.addFunction("string.encode_utf8_array", kSig_i_v)
.addBody([
kExprRefNull, kStringRefCode,
kExprRefNull, i8_array,
kExprI32Const, 0,
...GCInstr(kExprStringEncodeWtf8Array), kWtf8PolicyAccept
...GCInstr(kExprStringEncodeUtf8Array)
]);
builder.addFunction("string.encode_wtf8_array/reject", kSig_i_v)
builder.addFunction("string.encode_lossy_utf8_array", kSig_i_v)
.addBody([
kExprRefNull, kStringRefCode,
kExprRefNull, i8_array,
kExprI32Const, 0,
...GCInstr(kExprStringEncodeWtf8Array), kWtf8PolicyReject
...GCInstr(kExprStringEncodeLossyUtf8Array)
]);
builder.addFunction("string.encode_wtf8_array/replace", kSig_i_v)
builder.addFunction("string.encode_wtf8_array", kSig_i_v)
.addBody([
kExprRefNull, kStringRefCode,
kExprRefNull, i8_array,
kExprI32Const, 0,
...GCInstr(kExprStringEncodeWtf8Array), kWtf8PolicyReplace
...GCInstr(kExprStringEncodeWtf8Array)
]);
builder.addFunction("string.encode_wtf16_array", kSig_i_v)
......@@ -340,7 +325,7 @@ assertInvalid(
builder.addFunction("string.new_wtf8/no-mem", kSig_w_ii)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8), 0, kWtf8PolicyAccept
...GCInstr(kExprStringNewWtf8), 0
]);
},
/memory instruction with no memory/);
......@@ -351,7 +336,7 @@ assertInvalid(
builder.addFunction("string.new_wtf8/bad-mem", kSig_w_ii)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringNewWtf8), 1, kWtf8PolicyAccept
...GCInstr(kExprStringNewWtf8), 1
]);
},
/expected memory index 0, found 1/);
......@@ -361,7 +346,7 @@ assertInvalid(
builder.addFunction("string.encode_wtf8/no-mem", kSig_i_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringEncodeWtf8), 0, kWtf8PolicyAccept
...GCInstr(kExprStringEncodeWtf8), 0
]);
},
/memory instruction with no memory/);
......@@ -372,45 +357,11 @@ assertInvalid(
builder.addFunction("string.encode_wtf8/bad-mem", kSig_i_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringEncodeWtf8), 1, kWtf8PolicyAccept
...GCInstr(kExprStringEncodeWtf8), 1
]);
},
/expected memory index 0, found 1/);
assertInvalid(
builder => {
builder.addMemory(0, undefined, false, false);
builder.addFunction("string.encode_wtf8/bad-policy", kSig_i_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
...GCInstr(kExprStringEncodeWtf8), 0, 3
]);
},
/expected wtf8 policy 0, 1, or 2, but found 3/);
assertInvalid(
builder => {
builder.addFunction("string.measure_wtf8/bad-policy", kSig_i_w)
.addBody([
kExprLocalGet, 0,
...GCInstr(kExprStringMeasureWtf8), 3
]);
},
/expected wtf8 policy 0, 1, or 2, but found 3/);
assertInvalid(
builder => {
let i8_array = builder.addArray(kWasmI8, true);
builder.addFunction("string.new_wtf8_array/bad-policy", kSig_w_v)
.addBody([
kExprRefNull, i8_array,
kExprI32Const, 0,
kExprI32Const, 0,
...GCInstr(kExprStringNewWtf8Array), 3
]);
},
/expected wtf8 policy 0, 1, or 2, but found 3/);
assertInvalid(
builder => {
let i16_array = builder.addArray(kWasmI16, true);
......@@ -419,7 +370,7 @@ assertInvalid(
kExprRefNull, i16_array,
kExprI32Const, 0,
kExprI32Const, 0,
...GCInstr(kExprStringNewWtf8Array), kWtf8PolicyAccept
...GCInstr(kExprStringNewWtf8Array)
]);
},
/string.new_wtf8_array\[0\] expected array of i8, found ref.null of type \(ref null 0\)/);
......@@ -449,7 +400,7 @@ assertInvalid(
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprLocalGet, 2,
...GCInstr(kExprStringEncodeWtf8Array), kWtf8PolicyAccept,
...GCInstr(kExprStringEncodeWtf8Array)
]);
},
/string.encode_wtf8_array\[1\] expected array of mutable i8, found local.get of type \(ref 0\)/);
......
......@@ -526,20 +526,27 @@ let kExprBrOnNonI31 = 0x65;
let kExprBrOnNonArray = 0x67;
let kExprExternInternalize = 0x70;
let kExprExternExternalize = 0x71;
let kExprStringNewWtf8 = 0x80;
let kExprStringNewUtf8 = 0x80;
let kExprStringNewWtf16 = 0x81;
let kExprStringConst = 0x82;
let kExprStringMeasureUtf8 = 0x83;
let kExprStringMeasureWtf8 = 0x84;
let kExprStringMeasureWtf16 = 0x85;
let kExprStringEncodeWtf8 = 0x86;
let kExprStringEncodeUtf8 = 0x86;
let kExprStringEncodeWtf16 = 0x87;
let kExprStringConcat = 0x88;
let kExprStringEq = 0x89;
let kExprStringIsUsvSequence = 0x8a;
let kExprStringNewLossyUtf8 = 0x8b;
let kExprStringNewWtf8 = 0x8c;
let kExprStringEncodeLossyUtf8 = 0x8d;
let kExprStringEncodeWtf8 = 0x8e;
let kExprStringAsWtf8 = 0x90;
let kExprStringViewWtf8Advance = 0x91;
let kExprStringViewWtf8Encode = 0x92;
let kExprStringViewWtf8EncodeUtf8 = 0x92;
let kExprStringViewWtf8Slice = 0x93;
let kExprStringViewWtf8EncodeLossyUtf8 = 0x94;
let kExprStringViewWtf8EncodeWtf8 = 0x95;
let kExprStringAsWtf16 = 0x98;
let kExprStringViewWtf16Length = 0x99;
let kExprStringViewWtf16GetCodeunit = 0x9a;
......@@ -550,10 +557,14 @@ let kExprStringViewIterNext = 0xa1
let kExprStringViewIterAdvance = 0xa2;
let kExprStringViewIterRewind = 0xa3
let kExprStringViewIterSlice = 0xa4;
let kExprStringNewWtf8Array = 0xb0;
let kExprStringNewUtf8Array = 0xb0;
let kExprStringNewWtf16Array = 0xb1;
let kExprStringEncodeWtf8Array = 0xb2;
let kExprStringEncodeUtf8Array = 0xb2;
let kExprStringEncodeWtf16Array = 0xb3;
let kExprStringNewLossyUtf8Array = 0xb4;
let kExprStringNewWtf8Array = 0xb5;
let kExprStringEncodeLossyUtf8Array = 0xb6;
let kExprStringEncodeWtf8Array = 0xb7;
// Numeric opcodes.
let kExprI32SConvertSatF32 = 0x00;
......@@ -883,11 +894,6 @@ let kExprI32x4TruncSatF64x2UZero = 0xfd;
let kExprF64x2ConvertLowI32x4S = 0xfe;
let kExprF64x2ConvertLowI32x4U = 0xff;
// WTF-8 parsing policies.
let kWtf8PolicyReject = 0;
let kWtf8PolicyAccept = 1;
let kWtf8PolicyReplace = 2;
// Compilation hint constants.
let kCompilationHintStrategyDefault = 0x00;
let kCompilationHintStrategyLazy = 0x01;
......
......@@ -4864,8 +4864,8 @@ TEST_F(WasmOpcodeLengthTest, GCOpcodes) {
ExpectLength(3, 0xfb, 0x07, 0x42);
ExpectLength(4, 0xfb, 0x07, 0x80, 0x00);
// string.new_wtf8 with $mem=0, $policy=0.
ExpectLength(5, 0xfb, 0x80, 0x01, 0x00, 0x00);
// string.new_utf8 with $mem=0.
ExpectLength(4, 0xfb, 0x80, 0x01, 0x00);
// string.as_wtf8.
ExpectLength(3, 0xfb, 0x90, 0x01);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment