Commit 7a158c31 authored by Andy Wingo's avatar Andy Wingo Committed by V8 LUCI CQ

[stringrefs] Parse GC opcodes

Add parser support for wasm instructions that create stringrefs from GC
arrays, and which encode strings to GC arrays.

Bug: v8:12868
Change-Id: I38446855b7a55366f8107970811aec935defcdb4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3732935Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Andy Wingo <wingo@igalia.com>
Cr-Commit-Position: refs/heads/main@{#81440}
parent 46bd4afe
......@@ -6221,6 +6221,13 @@ class LiftoffCompiler {
__ PushRegister(kRef, result_reg);
}
void StringNewWtf8Array(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const Value& array, const Value& start,
const Value& end, Value* result) {
UNIMPLEMENTED();
}
void StringNewWtf16(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm,
const Value& offset, const Value& size, Value* result) {
......@@ -6245,6 +6252,12 @@ class LiftoffCompiler {
__ PushRegister(kRef, result_reg);
}
void StringNewWtf16Array(FullDecoder* decoder, const Value& array,
const Value& start, const Value& end,
Value* result) {
UNIMPLEMENTED();
}
void StringConst(FullDecoder* decoder,
const StringConstImmediate<validate>& imm, Value* result) {
LiftoffRegList pinned;
......@@ -6342,6 +6355,13 @@ class LiftoffCompiler {
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
}
void StringEncodeWtf8Array(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const Value& str, const Value& array,
const Value& start) {
UNIMPLEMENTED();
}
void StringEncodeWtf16(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm,
const Value& str, const Value& offset) {
......@@ -6372,6 +6392,11 @@ class LiftoffCompiler {
RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill);
}
void StringEncodeWtf16Array(FullDecoder* decoder, const Value& str,
const Value& array, const Value& start) {
UNIMPLEMENTED();
}
void StringConcat(FullDecoder* decoder, const Value& head, const Value& tail,
Value* result) {
LiftoffRegList pinned;
......
......@@ -1136,15 +1136,23 @@ struct ControlBase : public PcForErrors<validate> {
uint32_t br_depth) \
F(StringNewWtf8, const EncodeWtf8Immediate<validate>& imm, \
const Value& offset, const Value& size, Value* result) \
F(StringNewWtf8Array, const Wtf8PolicyImmediate<validate>& imm, \
const Value& array, const Value& start, const Value& end, Value* result) \
F(StringNewWtf16, const MemoryIndexImmediate<validate>& imm, \
const Value& offset, const Value& size, Value* result) \
F(StringNewWtf16Array, const Value& array, const Value& start, \
const Value& end, Value* result) \
F(StringMeasureWtf8, const Wtf8PolicyImmediate<validate>& imm, \
const Value& str, Value* result) \
F(StringMeasureWtf16, const Value& str, Value* result) \
F(StringEncodeWtf8, const EncodeWtf8Immediate<validate>& memory, \
const Value& str, const Value& address) \
F(StringEncodeWtf8Array, const Wtf8PolicyImmediate<validate>& imm, \
const Value& str, const Value& array, const Value& start) \
F(StringEncodeWtf16, const MemoryIndexImmediate<validate>& memory, \
const Value& str, const Value& address) \
F(StringEncodeWtf16Array, const Value& str, const Value& array, \
const Value& start) \
F(StringConcat, const Value& head, const Value& tail, Value* result) \
F(StringEq, const Value& a, const Value& b, Value* result) \
F(StringIsUSVSequence, const Value& str, Value* result) \
......@@ -2040,6 +2048,8 @@ class WasmDecoder : public Decoder {
StringConstImmediate<validate> imm(decoder, pc + length);
return length + imm.length;
}
case kExprStringNewWtf8Array:
case kExprStringEncodeWtf8Array:
case kExprStringMeasureWtf8: {
Wtf8PolicyImmediate<validate> imm(decoder, pc + length);
return length + imm.length;
......@@ -2060,6 +2070,8 @@ class WasmDecoder : public Decoder {
case kExprStringViewIterAdvance:
case kExprStringViewIterRewind:
case kExprStringViewIterSlice:
case kExprStringNewWtf16Array:
case kExprStringEncodeWtf16Array:
return length;
default:
// This is unreachable except for malformed modules.
......@@ -2283,8 +2295,12 @@ class WasmDecoder : public Decoder {
case kExprStringViewIterSlice:
return { 2, 1 };
case kExprStringEncodeWtf8:
case kExprStringEncodeWtf8Array:
case kExprStringEncodeWtf16:
case kExprStringEncodeWtf16Array:
return { 3, 0 };
case kExprStringNewWtf8Array:
case kExprStringNewWtf16Array:
case kExprStringViewWtf8Advance:
case kExprStringViewWtf8Slice:
case kExprStringViewWtf16Slice:
......@@ -5465,6 +5481,56 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
Push(result);
return opcode_length;
}
case kExprStringNewWtf8Array: {
CHECK_PROTOTYPE_OPCODE(gc);
NON_CONST_ONLY
Wtf8PolicyImmediate<validate> imm(this, this->pc_ + opcode_length);
Value array = PeekPackedArray(2, 0, kWasmI8);
Value start = Peek(1, 1, kWasmI32);
Value end = Peek(0, 2, kWasmI32);
Value result = CreateValue(kWasmStringRef);
CALL_INTERFACE_IF_OK_AND_REACHABLE(StringNewWtf8Array, imm, array,
start, end, &result);
Drop(3);
Push(result);
return opcode_length + imm.length;
}
case kExprStringNewWtf16Array: {
CHECK_PROTOTYPE_OPCODE(gc);
NON_CONST_ONLY
Value array = PeekPackedArray(2, 0, kWasmI16);
Value start = Peek(1, 1, kWasmI32);
Value end = Peek(0, 2, kWasmI32);
Value result = CreateValue(kWasmStringRef);
CALL_INTERFACE_IF_OK_AND_REACHABLE(StringNewWtf16Array, array, start,
end, &result);
Drop(3);
Push(result);
return opcode_length;
}
case kExprStringEncodeWtf8Array: {
CHECK_PROTOTYPE_OPCODE(gc);
NON_CONST_ONLY
Wtf8PolicyImmediate<validate> imm(this, this->pc_ + opcode_length);
Value str = Peek(2, 0, kWasmStringRef);
Value array = PeekPackedArray(1, 1, kWasmI8);
Value start = Peek(0, 2, kWasmI32);
CALL_INTERFACE_IF_OK_AND_REACHABLE(StringEncodeWtf8Array, imm, str,
array, start);
Drop(3);
return opcode_length + imm.length;
}
case kExprStringEncodeWtf16Array: {
CHECK_PROTOTYPE_OPCODE(gc);
NON_CONST_ONLY
Value str = Peek(2, 0, kWasmStringRef);
Value array = PeekPackedArray(1, 1, kWasmI16);
Value start = Peek(0, 2, kWasmI32);
CALL_INTERFACE_IF_OK_AND_REACHABLE(StringEncodeWtf16Array, str, array,
start);
Drop(3);
return opcode_length;
}
default:
this->DecodeError("invalid stringref opcode: %x", opcode);
return 0;
......@@ -5769,6 +5835,27 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
return *(stack_end_ - depth - 1);
}
Value PeekPackedArray(uint32_t stack_depth, uint32_t operand_index,
ValueType expected_element_type) {
Value array = Peek(stack_depth);
if (array.type.is_bottom()) {
// We are in a polymorphic stack. Leave the stack as it is.
DCHECK(!current_code_reachable_and_ok_);
return array;
}
if (VALIDATE(array.type.is_object_reference() && array.type.has_index())) {
uint32_t ref_index = array.type.ref_index();
if (VALIDATE(this->module_->has_array(ref_index) &&
this->module_->array_type(ref_index)->element_type() ==
expected_element_type)) {
return array;
}
}
PopTypeError(operand_index, array,
("array of " + expected_element_type.name()).c_str());
return array;
}
V8_INLINE void ValidateArgType(ArgVector args, int index,
ValueType expected) {
Value val = args[index];
......
......@@ -1404,12 +1404,25 @@ class WasmGraphBuildingInterface {
offset.node, size.node);
}
void StringNewWtf8Array(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const Value& array, const Value& start,
const Value& end, Value* result) {
UNIMPLEMENTED();
}
void StringNewWtf16(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm,
const Value& offset, const Value& size, Value* result) {
result->node = builder_->StringNewWtf16(imm.index, offset.node, size.node);
}
void StringNewWtf16Array(FullDecoder* decoder, const Value& array,
const Value& start, const Value& end,
Value* result) {
UNIMPLEMENTED();
}
void StringConst(FullDecoder* decoder,
const StringConstImmediate<validate>& imm, Value* result) {
result->node = builder_->StringConst(imm.index);
......@@ -1445,6 +1458,13 @@ class WasmGraphBuildingInterface {
decoder->position());
}
void StringEncodeWtf8Array(FullDecoder* decoder,
const Wtf8PolicyImmediate<validate>& imm,
const Value& str, const Value& array,
const Value& start) {
UNIMPLEMENTED();
}
void StringEncodeWtf16(FullDecoder* decoder,
const MemoryIndexImmediate<validate>& imm,
const Value& str, const Value& offset) {
......@@ -1452,6 +1472,11 @@ class WasmGraphBuildingInterface {
offset.node, decoder->position());
}
void StringEncodeWtf16Array(FullDecoder* decoder, const Value& str,
const Value& array, const Value& start) {
UNIMPLEMENTED();
}
void StringConcat(FullDecoder* decoder, const Value& head, const Value& tail,
Value* result) {
result->node =
......
......@@ -762,7 +762,11 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
V(StringViewIterCur, 0xfba1, _, "stringview_iter.cur") \
V(StringViewIterAdvance, 0xfba2, _, "stringview_iter.advance") \
V(StringViewIterRewind, 0xfba3, _, "stringview_iter.rewind") \
V(StringViewIterSlice, 0xfba4, _, "stringview_iter.slice")
V(StringViewIterSlice, 0xfba4, _, "stringview_iter.slice") \
V(StringNewWtf8Array, 0xfbb0, _, "string.new_wtf8_array") \
V(StringNewWtf16Array, 0xfbb1, _, "string.new_wtf16_array") \
V(StringEncodeWtf8Array, 0xfbb2, _, "string.encode_wtf8_array") \
V(StringEncodeWtf16Array, 0xfbb3, _, "string.encode_wtf16_array")
// All opcodes.
#define FOREACH_OPCODE(V) \
......
......@@ -106,19 +106,19 @@ let kSig_w_zi = makeSig([kWasmStringViewIter, kWasmI32],
builder.addFunction("string.measure_wtf8/utf-8", kSig_i_w)
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprStringMeasureWtf8, 0
kGCPrefix, kExprStringMeasureWtf8, kWtf8PolicyReject
]);
builder.addFunction("string.measure_wtf8/wtf-8", kSig_i_w)
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprStringMeasureWtf8, 1
kGCPrefix, kExprStringMeasureWtf8, kWtf8PolicyAccept
]);
builder.addFunction("string.measure_wtf8/replace", kSig_i_w)
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprStringMeasureWtf8, 2
kGCPrefix, kExprStringMeasureWtf8, kWtf8PolicyReplace
]);
builder.addFunction("string.measure_wtf16", kSig_i_w)
......@@ -130,17 +130,17 @@ let kSig_w_zi = makeSig([kWasmStringViewIter, kWasmI32],
builder.addFunction("string.encode_wtf8/utf-8", kSig_v_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprStringEncodeWtf8, 0, 0
kGCPrefix, kExprStringEncodeWtf8, 0, kWtf8PolicyAccept
]);
builder.addFunction("string.encode_wtf8/wtf-8", kSig_v_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprStringEncodeWtf8, 0, 1
kGCPrefix, kExprStringEncodeWtf8, 0, kWtf8PolicyReject
]);
builder.addFunction("string.encode_wtf8/replace", kSig_v_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprStringEncodeWtf8, 0, 2
kGCPrefix, kExprStringEncodeWtf8, 0, kWtf8PolicyReplace
]);
builder.addFunction("string.encode_wtf16", kSig_v_wi)
......@@ -257,6 +257,73 @@ let kSig_w_zi = makeSig([kWasmStringViewIter, kWasmI32],
kGCPrefix, kExprStringViewIterSlice
]);
let i8_array = builder.addArray(kWasmI8, true);
let i16_array = builder.addArray(kWasmI16, true);
builder.addFunction("string.new_wtf8_array/accept", kSig_w_v)
.addBody([
kExprRefNull, i8_array,
kExprI32Const, 0,
kExprI32Const, 0,
kGCPrefix, kExprStringNewWtf8Array, kWtf8PolicyAccept
]);
builder.addFunction("string.new_wtf8_array/reject", kSig_w_v)
.addBody([
kExprRefNull, i8_array,
kExprI32Const, 0,
kExprI32Const, 0,
kGCPrefix, kExprStringNewWtf8Array, kWtf8PolicyReject
]);
builder.addFunction("string.new_wtf8_array/replace", kSig_w_v)
.addBody([
kExprRefNull, i8_array,
kExprI32Const, 0,
kExprI32Const, 0,
kGCPrefix, kExprStringNewWtf8Array, kWtf8PolicyReplace
]);
builder.addFunction("string.new_wtf16_array", kSig_w_v)
.addBody([
kExprRefNull, i16_array,
kExprI32Const, 0,
kExprI32Const, 0,
kGCPrefix, kExprStringNewWtf16Array
]);
builder.addFunction("string.encode_wtf8_array/accept", kSig_v_v)
.addBody([
kExprRefNull, kStringRefCode,
kExprRefNull, i8_array,
kExprI32Const, 0,
kGCPrefix, kExprStringEncodeWtf8Array, kWtf8PolicyAccept
]);
builder.addFunction("string.encode_wtf8_array/reject", kSig_v_v)
.addBody([
kExprRefNull, kStringRefCode,
kExprRefNull, i8_array,
kExprI32Const, 0,
kGCPrefix, kExprStringEncodeWtf8Array, kWtf8PolicyReject
]);
builder.addFunction("string.encode_wtf8_array/replace", kSig_v_v)
.addBody([
kExprRefNull, kStringRefCode,
kExprRefNull, i8_array,
kExprI32Const, 0,
kGCPrefix, kExprStringEncodeWtf8Array, kWtf8PolicyReplace
]);
builder.addFunction("string.encode_wtf16_array", kSig_v_v)
.addBody([
kExprRefNull, kStringRefCode,
kExprRefNull, i16_array,
kExprI32Const, 0,
kGCPrefix, kExprStringEncodeWtf16Array
]);
assertTrue(WebAssembly.validate(builder.toBuffer()));
})();
......@@ -298,7 +365,7 @@ assertInvalid(
builder.addFunction("string.encode_wtf8/no-mem", kSig_v_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprStringEncodeWtf8, 0, 0
kGCPrefix, kExprStringEncodeWtf8, 0, kWtf8PolicyAccept
]);
},
"Compiling function #0:\"string.encode_wtf8/no-mem\" failed: " +
......@@ -310,7 +377,7 @@ assertInvalid(
builder.addFunction("string.encode_wtf8/bad-mem", kSig_v_wi)
.addBody([
kExprLocalGet, 0, kExprLocalGet, 1,
kGCPrefix, kExprStringEncodeWtf8, 1, 0
kGCPrefix, kExprStringEncodeWtf8, 1, kWtf8PolicyAccept
]);
},
"Compiling function #0:\"string.encode_wtf8/bad-mem\" failed: " +
......@@ -338,3 +405,47 @@ assertInvalid(
},
"Compiling function #0:\"string.measure_wtf8/bad-policy\" failed: " +
"expected wtf8 policy 0, 1, or 2, but found 3 @+29");
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,
kGCPrefix, kExprStringNewWtf8Array, 3
]);
},
"Compiling function #0:\"string.new_wtf8_array/bad-policy\" failed: " +
"expected wtf8 policy 0, 1, or 2, but found 3 @+35");
assertInvalid(
builder => {
let i16_array = builder.addArray(kWasmI16, true);
builder.addFunction("string.new_wtf8_array/bad-type", kSig_w_v)
.addBody([
kExprRefNull, i16_array,
kExprI32Const, 0,
kExprI32Const, 0,
kGCPrefix, kExprStringNewWtf8Array, kWtf8PolicyAccept
]);
},
"Compiling function #0:\"string.new_wtf8_array/bad-type\" failed: " +
"string.new_wtf8_array[0] expected array of i8, " +
"found ref.null of type (ref null 0) @+27");
assertInvalid(
builder => {
let i8_array = builder.addArray(kWasmI8, true);
builder.addFunction("string.new_wtf16_array/bad-type", kSig_w_v)
.addBody([
kExprRefNull, i8_array,
kExprI32Const, 0,
kExprI32Const, 0,
kGCPrefix, kExprStringNewWtf16Array
]);
},
"Compiling function #0:\"string.new_wtf16_array/bad-type\" failed: " +
"string.new_wtf16_array[0] expected array of i16, " +
"found ref.null of type (ref null 0) @+27");
......@@ -557,6 +557,10 @@ let kExprStringViewIterCur = 0xa1
let kExprStringViewIterAdvance = 0xa2;
let kExprStringViewIterRewind = 0xa3
let kExprStringViewIterSlice = 0xa4;
let kExprStringNewWtf8Array = 0xb0;
let kExprStringNewWtf16Array = 0xb1;
let kExprStringEncodeWtf8Array = 0xb2;
let kExprStringEncodeWtf16Array = 0xb3;
// Numeric opcodes.
let kExprI32SConvertSatF32 = 0x00;
......
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