[wasm-gc] Implement rtt.canon
along with a very basic test case. Bug: v8:7748 Change-Id: I93d4b280922dd9eba8defc1a83ca08a2a957376a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2254023 Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#68485}
This commit is contained in:
parent
0034015b1a
commit
906db63ff4
@ -5279,6 +5279,22 @@ Node* WasmGraphBuilder::ArrayNew(uint32_t array_index,
|
||||
return a;
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::RttCanon(uint32_t type_index) {
|
||||
// This logic is duplicated from module-instantiate.cc.
|
||||
// TODO(jkummerow): Find a nicer solution.
|
||||
int map_index = 0;
|
||||
const std::vector<uint8_t>& type_kinds = env_->module->type_kinds;
|
||||
for (uint32_t i = 0; i < type_index; i++) {
|
||||
if (type_kinds[i] == wasm::kWasmStructTypeCode ||
|
||||
type_kinds[i] == wasm::kWasmArrayTypeCode) {
|
||||
map_index++;
|
||||
}
|
||||
}
|
||||
Node* maps_list =
|
||||
LOAD_INSTANCE_FIELD(ManagedObjectMaps, MachineType::TaggedPointer());
|
||||
return LOAD_FIXED_ARRAY_SLOT_PTR(maps_list, type_index);
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::StructGet(Node* struct_object,
|
||||
const wasm::StructType* struct_type,
|
||||
uint32_t field_index, CheckForNull null_check,
|
||||
@ -5580,10 +5596,11 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
return BuildChangeFloat64ToNumber(node);
|
||||
case wasm::ValueType::kRef:
|
||||
case wasm::ValueType::kOptRef:
|
||||
// TODO(7748): Implement properly for arrays and structs.
|
||||
case wasm::ValueType::kRtt:
|
||||
// TODO(7748): Implement properly for arrays and structs, figure
|
||||
// out what to do for RTTs.
|
||||
// For now, we just expose the raw object for testing.
|
||||
return node;
|
||||
case wasm::ValueType::kRtt:
|
||||
case wasm::ValueType::kI8:
|
||||
case wasm::ValueType::kI16:
|
||||
UNIMPLEMENTED();
|
||||
|
@ -397,6 +397,7 @@ class WasmGraphBuilder {
|
||||
Node* ArraySet(Node* array_object, const wasm::ArrayType* type, Node* index,
|
||||
Node* value, wasm::WasmCodePosition position);
|
||||
Node* ArrayLen(Node* array_object, wasm::WasmCodePosition position);
|
||||
Node* RttCanon(uint32_t type_index);
|
||||
|
||||
bool has_simd() const { return has_simd_; }
|
||||
|
||||
|
@ -3609,6 +3609,12 @@ class LiftoffCompiler {
|
||||
unsupported(decoder, kGC, "array.len");
|
||||
}
|
||||
|
||||
void RttCanon(FullDecoder* decoder, const TypeIndexImmediate<validate>& imm,
|
||||
Value* result) {
|
||||
// TODO(7748): Implement.
|
||||
unsupported(decoder, kGC, "rtt.canon");
|
||||
}
|
||||
|
||||
void PassThrough(FullDecoder* decoder, const Value& from, Value* to) {
|
||||
// TODO(7748): Implement.
|
||||
unsupported(decoder, kGC, "");
|
||||
|
@ -212,8 +212,30 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
|
||||
#undef REF_TYPE_CASE
|
||||
case kLocalRtt:
|
||||
if (enabled.has_gc()) {
|
||||
// TODO(7748): Implement
|
||||
decoder->error(pc, "'rtt' is unimplemented");
|
||||
uint32_t depth_length;
|
||||
uint32_t depth =
|
||||
decoder->read_u32v<validate>(pc + 1, &depth_length, "depth");
|
||||
// TODO(7748): Introduce a proper limit.
|
||||
const uint32_t kMaxRttSubtypingDepth = 7;
|
||||
if (!VALIDATE(depth <= kMaxRttSubtypingDepth)) {
|
||||
decoder->errorf(pc,
|
||||
"subtyping depth %u is greater than the maximum "
|
||||
"depth %u supported by V8",
|
||||
depth, kMaxRttSubtypingDepth);
|
||||
return kWasmBottom;
|
||||
}
|
||||
uint32_t type_index = decoder->read_u32v<validate>(
|
||||
pc + 1 + depth_length, length, "type index");
|
||||
if (!VALIDATE(type_index < kV8MaxWasmTypes)) {
|
||||
decoder->errorf(pc,
|
||||
"Type index %u is greater than the maximum "
|
||||
"number %zu of type definitions supported by V8",
|
||||
type_index, kV8MaxWasmTypes);
|
||||
return kWasmBottom;
|
||||
}
|
||||
*length += 1 + depth_length;
|
||||
return ValueType::Rtt(static_cast<HeapType>(type_index),
|
||||
static_cast<uint8_t>(depth));
|
||||
}
|
||||
decoder->error(
|
||||
pc, "invalid value type 'rtt', enable with --experimental-wasm-gc");
|
||||
@ -493,6 +515,17 @@ struct ArrayIndexImmediate {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(jkummerow): Make this a superclass of StructIndexImmediate and
|
||||
// ArrayIndexImmediate? Maybe even FunctionIndexImmediate too?
|
||||
template <Decoder::ValidateFlag validate>
|
||||
struct TypeIndexImmediate {
|
||||
uint32_t index = 0;
|
||||
uint32_t length = 0;
|
||||
inline TypeIndexImmediate(Decoder* decoder, const byte* pc) {
|
||||
index = decoder->read_u32v<validate>(pc, &length, "type index");
|
||||
}
|
||||
};
|
||||
|
||||
template <Decoder::ValidateFlag validate>
|
||||
struct CallIndirectImmediate {
|
||||
uint32_t table_index;
|
||||
@ -924,6 +957,7 @@ struct ControlBase {
|
||||
const ArrayIndexImmediate<validate>& imm, const Value& index, \
|
||||
const Value& value) \
|
||||
F(ArrayLen, const Value& array_obj, Value* result) \
|
||||
F(RttCanon, const TypeIndexImmediate<validate>& imm, Value* result) \
|
||||
F(PassThrough, const Value& from, Value* to)
|
||||
|
||||
// Generic Wasm bytecode decoder with utilities for decoding immediates,
|
||||
@ -1155,6 +1189,15 @@ class WasmDecoder : public Decoder {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Validate(const byte* pc, TypeIndexImmediate<validate>& imm) {
|
||||
if (!VALIDATE(module_ != nullptr && (module_->has_struct(imm.index) ||
|
||||
module_->has_array(imm.index)))) {
|
||||
errorf(pc, "invalid type index: %u", imm.index);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool CanReturnCall(const FunctionSig* target_sig) {
|
||||
if (target_sig == nullptr) return false;
|
||||
size_t num_returns = sig_->return_count();
|
||||
@ -1639,10 +1682,14 @@ class WasmDecoder : public Decoder {
|
||||
BranchDepthImmediate<validate> imm(decoder, pc + 2);
|
||||
return 2 + imm.length;
|
||||
}
|
||||
case kExprRttGet:
|
||||
case kExprRttCanon: {
|
||||
// TODO(7748): Introduce "HeapTypeImmediate" and use it here.
|
||||
TypeIndexImmediate<validate> heaptype(decoder, pc + 2);
|
||||
return 2 + heaptype.length;
|
||||
}
|
||||
case kExprRttSub: {
|
||||
// TODO(7748): Implement.
|
||||
decoder->error(pc, "rtt opcodes not implemented yet");
|
||||
decoder->error(pc, "rtt.sub not implemented yet");
|
||||
return 2;
|
||||
}
|
||||
|
||||
@ -3403,6 +3450,16 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
CALL_INTERFACE_IF_REACHABLE(ArrayLen, array_obj, value);
|
||||
break;
|
||||
}
|
||||
case kExprRttCanon: {
|
||||
// TODO(7748): Introduce HeapTypeImmediate and use that here.
|
||||
TypeIndexImmediate<validate> imm(this, this->pc_ + len);
|
||||
len += imm.length;
|
||||
if (!this->Validate(this->pc_ + len, imm)) break;
|
||||
Value* value =
|
||||
Push(ValueType::Rtt(static_cast<HeapType>(imm.index), 1));
|
||||
CALL_INTERFACE_IF_REACHABLE(RttCanon, imm, value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this->error("invalid gc opcode");
|
||||
return 0;
|
||||
|
@ -701,6 +701,11 @@ class WasmGraphBuildingInterface {
|
||||
result->node = BUILD(ArrayLen, array_obj.node, decoder->position());
|
||||
}
|
||||
|
||||
void RttCanon(FullDecoder* decoder, const TypeIndexImmediate<validate>& imm,
|
||||
Value* result) {
|
||||
result->node = BUILD(RttCanon, imm.index);
|
||||
}
|
||||
|
||||
void PassThrough(FullDecoder* decoder, const Value& from, Value* to) {
|
||||
to->node = from.node;
|
||||
}
|
||||
|
@ -1729,7 +1729,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
this, this->pc(), &type_length,
|
||||
origin_ == kWasmOrigin ? enabled_features_ : WasmFeatures::None());
|
||||
if (result == kWasmBottom) error(pc_, "invalid value type");
|
||||
consume_bytes(type_length);
|
||||
consume_bytes(type_length, "value type");
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1737,10 +1737,10 @@ class ModuleDecoderImpl : public Decoder {
|
||||
uint8_t opcode = read_u8<kValidate>(this->pc());
|
||||
switch (opcode) {
|
||||
case kLocalI8:
|
||||
consume_bytes(1);
|
||||
consume_bytes(1, "i8");
|
||||
return kWasmI8;
|
||||
case kLocalI16:
|
||||
consume_bytes(1);
|
||||
consume_bytes(1, "i16");
|
||||
return kWasmI16;
|
||||
default:
|
||||
// It is not a packed type, so it has to be a value type.
|
||||
|
@ -180,6 +180,8 @@ class ValueType {
|
||||
return kLocalRef;
|
||||
case kStmt:
|
||||
return kLocalVoid;
|
||||
case kRtt:
|
||||
return kLocalRtt;
|
||||
default:
|
||||
return static_cast<ValueTypeCode>(kLocalI32 - (kind() - kI32));
|
||||
}
|
||||
|
@ -1847,6 +1847,8 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
}
|
||||
break;
|
||||
case i::wasm::ValueType::kRtt:
|
||||
UNIMPLEMENTED(); // TODO(7748): Implement.
|
||||
break;
|
||||
case i::wasm::ValueType::kI8:
|
||||
case i::wasm::ValueType::kI16:
|
||||
case i::wasm::ValueType::kBottom:
|
||||
|
@ -415,7 +415,7 @@ namespace {
|
||||
void WriteValueType(ZoneBuffer* buffer, const ValueType& type) {
|
||||
buffer->write_u8(type.value_type_code());
|
||||
if (type.has_depth()) {
|
||||
buffer->write_u8(type.depth());
|
||||
buffer->write_u32v(type.depth());
|
||||
}
|
||||
if (type.encoding_needs_heap_type()) {
|
||||
buffer->write_u32v(type.heap_type_code());
|
||||
@ -598,15 +598,13 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
|
||||
case ValueType::kOptRef:
|
||||
buffer->write_u8(kExprRefNull);
|
||||
break;
|
||||
case ValueType::kRtt:
|
||||
// TODO(7748): Implement.
|
||||
break;
|
||||
case ValueType::kI8:
|
||||
case ValueType::kI16:
|
||||
case ValueType::kStmt:
|
||||
case ValueType::kS128:
|
||||
case ValueType::kBottom:
|
||||
case ValueType::kRef:
|
||||
case ValueType::kRtt:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
|
||||
CASE_OP(I31New, "i31.new")
|
||||
CASE_OP(I31GetS, "i31.get_s")
|
||||
CASE_OP(I31GetU, "i31.get_u")
|
||||
CASE_OP(RttGet, "rtt.get")
|
||||
CASE_OP(RttCanon, "rtt.canon")
|
||||
CASE_OP(RttSub, "rtt.sub")
|
||||
CASE_OP(RefTest, "ref.test")
|
||||
CASE_OP(RefCast, "ref.cast")
|
||||
|
@ -617,7 +617,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
|
||||
V(I31New, 0xfb20, _) \
|
||||
V(I31GetS, 0xfb21, _) \
|
||||
V(I31GetU, 0xfb22, _) \
|
||||
V(RttGet, 0xfb30, _) \
|
||||
V(RttCanon, 0xfb30, _) \
|
||||
V(RttSub, 0xfb31, _) \
|
||||
V(RefTest, 0xfb40, _) \
|
||||
V(RefCast, 0xfb41, _) \
|
||||
|
@ -34,12 +34,10 @@ class WasmGCTester {
|
||||
flag_reftypes(&v8::internal::FLAG_experimental_wasm_reftypes, true),
|
||||
flag_typedfuns(&v8::internal::FLAG_experimental_wasm_typed_funcref,
|
||||
true),
|
||||
allocator(),
|
||||
zone(&allocator, ZONE_NAME),
|
||||
builder(&zone),
|
||||
isolate(CcTest::InitIsolateOnce()),
|
||||
scope(isolate),
|
||||
instance(),
|
||||
thrower(isolate, "Test wasm GC") {
|
||||
testing::SetupIsolateForWasmModule(isolate);
|
||||
}
|
||||
@ -80,7 +78,7 @@ class WasmGCTester {
|
||||
testing::CompileAndInstantiateForTesting(
|
||||
isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
|
||||
if (thrower.error()) FATAL("%s", thrower.error_msg());
|
||||
instance = maybe_instance.ToHandleChecked();
|
||||
instance_ = maybe_instance.ToHandleChecked();
|
||||
}
|
||||
|
||||
void CheckResult(const char* function, int32_t expected,
|
||||
@ -91,7 +89,7 @@ class WasmGCTester {
|
||||
argv[i++] = handle(arg, isolate);
|
||||
}
|
||||
CHECK_EQ(expected, testing::CallWasmFunctionForTesting(
|
||||
isolate, instance, &thrower, function,
|
||||
isolate, instance_, &thrower, function,
|
||||
static_cast<uint32_t>(args.size()), argv));
|
||||
}
|
||||
|
||||
@ -106,7 +104,7 @@ class WasmGCTester {
|
||||
argv[i++] = handle(arg, isolate);
|
||||
}
|
||||
Handle<WasmExportedFunction> exported =
|
||||
testing::GetExportedFunction(isolate, instance, function)
|
||||
testing::GetExportedFunction(isolate, instance_, function)
|
||||
.ToHandleChecked();
|
||||
return Execution::Call(isolate, exported,
|
||||
isolate->factory()->undefined_value(),
|
||||
@ -122,6 +120,8 @@ class WasmGCTester {
|
||||
isolate->clear_pending_exception();
|
||||
}
|
||||
|
||||
Handle<WasmInstanceObject> instance() { return instance_; }
|
||||
|
||||
TestSignatures sigs;
|
||||
|
||||
private:
|
||||
@ -135,7 +135,7 @@ class WasmGCTester {
|
||||
|
||||
Isolate* const isolate;
|
||||
const HandleScope scope;
|
||||
Handle<WasmInstanceObject> instance;
|
||||
Handle<WasmInstanceObject> instance_;
|
||||
ErrorThrower thrower;
|
||||
};
|
||||
|
||||
@ -544,6 +544,28 @@ TEST(WasmPackedArrayS) {
|
||||
{Smi::FromInt(3)});
|
||||
}
|
||||
|
||||
TEST(BasicRTT) {
|
||||
WasmGCTester tester;
|
||||
uint32_t type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
|
||||
ValueType kRttTypes[] = {
|
||||
ValueType::Rtt(static_cast<HeapType>(type_index), 1)};
|
||||
FunctionSig sig_t_v(1, 0, kRttTypes);
|
||||
|
||||
tester.DefineFunction("f", &sig_t_v, {},
|
||||
{WASM_RTT_CANON(type_index), kExprEnd});
|
||||
|
||||
tester.CompileModule();
|
||||
|
||||
Handle<Object> ref_result = tester.GetJSResult("f", {}).ToHandleChecked();
|
||||
|
||||
CHECK(ref_result->IsMap());
|
||||
Handle<Map> map = Handle<Map>::cast(ref_result);
|
||||
CHECK(map->IsWasmStructMap());
|
||||
CHECK_EQ(reinterpret_cast<Address>(
|
||||
tester.instance()->module()->struct_type(type_index)),
|
||||
map->wasm_type_info().foreign_address());
|
||||
}
|
||||
|
||||
} // namespace test_gc
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
|
@ -3723,7 +3723,7 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
case ValueType::kRtt:
|
||||
// TODO(7748): Implement properly.
|
||||
PrintF("ref/ref null/rtt");
|
||||
PrintF("rtt");
|
||||
break;
|
||||
case ValueType::kI8:
|
||||
case ValueType::kI16:
|
||||
|
@ -459,6 +459,9 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
|
||||
#define WASM_ARRAY_LEN(typeidx, array) \
|
||||
array, WASM_GC_OP(kExprArrayLen), static_cast<byte>(typeidx)
|
||||
|
||||
#define WASM_RTT_CANON(typeidx) \
|
||||
WASM_GC_OP(kExprRttCanon), static_cast<byte>(typeidx)
|
||||
|
||||
#define WASM_BR_ON_NULL(depth, ref_object) \
|
||||
ref_object, kExprBrOnNull, static_cast<byte>(depth)
|
||||
// Pass: sig_index, ...args, func_index
|
||||
|
Loading…
Reference in New Issue
Block a user