Commit 57c8f1da authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Refactor GC tests

Add some abstractions to make it easier to define more tests.

Bug: v8:7748
Change-Id: Ia5605aa10963228eb4bfba37e2b412fc5af860d8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2224212
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68147}
parent dc618604
...@@ -25,101 +25,197 @@ namespace internal { ...@@ -25,101 +25,197 @@ namespace internal {
namespace wasm { namespace wasm {
namespace test_gc { namespace test_gc {
WASM_EXEC_TEST(BasicStruct) { using F = std::pair<ValueType, bool>;
// TODO(7748): Implement support in other tiers.
if (execution_tier == ExecutionTier::kLiftoff) return; class WasmGCTester {
if (execution_tier == ExecutionTier::kInterpreter) return; public:
WasmGCTester()
: flag_gc(&v8::internal::FLAG_experimental_wasm_gc, true),
flag_reftypes(&v8::internal::FLAG_experimental_wasm_anyref, 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);
}
uint32_t AddGlobal(ValueType type, bool mutability, WasmInitExpr init) {
return builder.AddGlobal(type, mutability, init);
}
void DefineFunction(const char* name, FunctionSig* sig,
std::initializer_list<ValueType> locals,
std::initializer_list<byte> code) {
WasmFunctionBuilder* fun = builder.AddFunction(sig);
builder.AddExport(CStrVector(name), fun);
for (ValueType local : locals) {
fun->AddLocal(local);
}
fun->EmitCode(code.begin(), static_cast<uint32_t>(code.size()));
}
uint32_t DefineStruct(std::initializer_list<F> fields) {
StructType::Builder type_builder(&zone,
static_cast<uint32_t>(fields.size()));
for (F field : fields) {
type_builder.AddField(field.first, field.second);
}
return builder.AddStructType(type_builder.Build());
}
uint32_t DefineArray(ValueType element_type, bool mutability) {
return builder.AddArrayType(new (&zone)
ArrayType(element_type, mutability));
}
void CompileModule() {
ZoneBuffer buffer(&zone);
builder.WriteTo(&buffer);
MaybeHandle<WasmInstanceObject> maybe_instance =
testing::CompileAndInstantiateForTesting(
isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
if (thrower.error()) FATAL("%s", thrower.error_msg());
instance = maybe_instance.ToHandleChecked();
}
void CheckResult(const char* function, int32_t expected,
std::initializer_list<Object> args) {
Handle<Object>* argv = zone.NewArray<Handle<Object>>(args.size());
int i = 0;
for (Object arg : args) {
argv[i++] = handle(arg, isolate);
}
CHECK_EQ(expected, testing::CallWasmFunctionForTesting(
isolate, instance, &thrower, function,
static_cast<uint32_t>(args.size()), argv));
}
// TODO(7748): This uses the JavaScript interface to retrieve the plain
// WasmStruct. Once the JS interaction story is settled, this may well
// need to be changed.
MaybeHandle<Object> GetJSResult(const char* function,
std::initializer_list<Object> args) {
Handle<Object>* argv = zone.NewArray<Handle<Object>>(args.size());
int i = 0;
for (Object arg : args) {
argv[i++] = handle(arg, isolate);
}
Handle<WasmExportedFunction> exported =
testing::GetExportedFunction(isolate, instance, function)
.ToHandleChecked();
return Execution::Call(isolate, exported,
isolate->factory()->undefined_value(),
static_cast<uint32_t>(args.size()), argv);
}
void CheckHasThrown(const char* function,
std::initializer_list<Object> args) {
TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
MaybeHandle<Object> result = GetJSResult(function, args);
CHECK(result.is_null());
CHECK(try_catch.HasCaught());
isolate->clear_pending_exception();
}
TestSignatures sigs; TestSignatures sigs;
EXPERIMENTAL_FLAG_SCOPE(gc);
EXPERIMENTAL_FLAG_SCOPE(anyref);
v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME);
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone); private:
StructType::Builder type_builder(&zone, 2); const FlagScope<bool> flag_gc;
type_builder.AddField(kWasmI32, true); const FlagScope<bool> flag_reftypes;
type_builder.AddField(kWasmI32, true); const FlagScope<bool> flag_typedfuns;
int32_t type_index = builder->AddStructType(type_builder.Build());
v8::internal::AccountingAllocator allocator;
Zone zone;
WasmModuleBuilder builder;
Isolate* const isolate;
const HandleScope scope;
Handle<WasmInstanceObject> instance;
ErrorThrower thrower;
};
// TODO(7748): Use WASM_EXEC_TEST once interpreter and liftoff are supported
TEST(WasmBasicStruct) {
WasmGCTester tester;
uint32_t type_index =
tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)}; ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)};
ValueType kOptRefType = ValueType(ValueType::kOptRef, type_index); ValueType kOptRefType = ValueType(ValueType::kOptRef, type_index);
FunctionSig sig_q_v(1, 0, kRefTypes); FunctionSig sig_q_v(1, 0, kRefTypes);
// Test struct.new and struct.get. // Test struct.new and struct.get.
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
f->builder()->AddExport(CStrVector("f"), f); tester.DefineFunction(
byte f_code[] = {WASM_STRUCT_GET(type_index, 0, "f", tester.sigs.i_v(), {},
WASM_STRUCT_NEW(type_index, WASM_I32V(42), {WASM_STRUCT_GET(
WASM_I32V(64))), type_index, 0,
kExprEnd}; WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(64))),
f->EmitCode(f_code, sizeof(f_code)); kExprEnd});
// Test struct.new and struct.get. // Test struct.new and struct.get.
WasmFunctionBuilder* g = builder->AddFunction(sigs.i_v()); tester.DefineFunction(
g->builder()->AddExport(CStrVector("g"), g); "g", tester.sigs.i_v(), {},
byte g_code[] = {WASM_STRUCT_GET(type_index, 1, {WASM_STRUCT_GET(
WASM_STRUCT_NEW(type_index, WASM_I32V(42), type_index, 1,
WASM_I32V(64))), WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(64))),
kExprEnd}; kExprEnd});
g->EmitCode(g_code, sizeof(g_code));
// Test struct.new, returning struct references to JS. // Test struct.new, returning struct references to JS.
WasmFunctionBuilder* h = builder->AddFunction(&sig_q_v); tester.DefineFunction(
h->builder()->AddExport(CStrVector("h"), h); "h", &sig_q_v, {},
byte h_code[] = {WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(64)), {WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(64)), kExprEnd});
kExprEnd};
h->EmitCode(h_code, sizeof(h_code));
// Test struct.set, struct refs types in locals. // Test struct.set, struct refs types in locals.
WasmFunctionBuilder* j = builder->AddFunction(sigs.i_v()); uint32_t j_local_index = 0;
uint32_t j_local_index = j->AddLocal(kOptRefType);
uint32_t j_field_index = 0; uint32_t j_field_index = 0;
j->builder()->AddExport(CStrVector("j"), j); tester.DefineFunction(
byte j_code[] = { "j", tester.sigs.i_v(), {kOptRefType},
WASM_SET_LOCAL(j_local_index, {WASM_SET_LOCAL(j_local_index, WASM_STRUCT_NEW(type_index, WASM_I32V(42),
WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(64))), WASM_I32V(64))),
WASM_STRUCT_SET(type_index, j_field_index, WASM_GET_LOCAL(j_local_index), WASM_STRUCT_SET(type_index, j_field_index, WASM_GET_LOCAL(j_local_index),
WASM_I32V(-99)), WASM_I32V(-99)),
WASM_STRUCT_GET(type_index, j_field_index, WASM_GET_LOCAL(j_local_index)), WASM_STRUCT_GET(type_index, j_field_index,
kExprEnd}; WASM_GET_LOCAL(j_local_index)),
j->EmitCode(j_code, sizeof(j_code)); kExprEnd});
// Test struct.set, ref.as_non_null, // Test struct.set, ref.as_non_null,
// struct refs types in globals and if-results. // struct refs types in globals and if-results.
uint32_t k_global_index = builder->AddGlobal( uint32_t k_global_index = tester.AddGlobal(
kOptRefType, true, WasmInitExpr(WasmInitExpr::kRefNullConst)); kOptRefType, true, WasmInitExpr(WasmInitExpr::kRefNullConst));
WasmFunctionBuilder* k = builder->AddFunction(sigs.i_v());
uint32_t k_field_index = 0; uint32_t k_field_index = 0;
k->builder()->AddExport(CStrVector("k"), k); tester.DefineFunction(
byte k_code[] = { "k", tester.sigs.i_v(), {},
WASM_SET_GLOBAL(k_global_index, WASM_STRUCT_NEW(type_index, WASM_I32V(55), {WASM_SET_GLOBAL(
WASM_I32V(66))), k_global_index,
WASM_STRUCT_NEW(type_index, WASM_I32V(55), WASM_I32V(66))),
WASM_STRUCT_GET( WASM_STRUCT_GET(
type_index, k_field_index, type_index, k_field_index,
WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(kOptRefType, WASM_I32V(1), WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(kOptRefType, WASM_I32V(1),
WASM_GET_GLOBAL(k_global_index), WASM_GET_GLOBAL(k_global_index),
WASM_REF_NULL_GC(type_index)))), WASM_REF_NULL_GC(type_index)))),
kExprEnd}; kExprEnd});
k->EmitCode(k_code, sizeof(k_code));
// Test br_on_null 1. // Test br_on_null 1.
WasmFunctionBuilder* l = builder->AddFunction(sigs.i_v()); uint32_t l_local_index = 0;
uint32_t l_local_index = l->AddLocal(kOptRefType); tester.DefineFunction(
l->builder()->AddExport(CStrVector("l"), l); "l", tester.sigs.i_v(), {kOptRefType},
byte l_code[] = { {WASM_BLOCK_I(WASM_I32V(42),
WASM_BLOCK_I(WASM_I32V(42),
// Branch will be taken. // Branch will be taken.
// 42 left on stack outside the block (not 52). // 42 left on stack outside the block (not 52).
WASM_BR_ON_NULL(0, WASM_GET_LOCAL(l_local_index)), WASM_BR_ON_NULL(0, WASM_GET_LOCAL(l_local_index)),
WASM_I32V(52), WASM_BR(0)), WASM_I32V(52), WASM_BR(0)),
kExprEnd}; kExprEnd});
l->EmitCode(l_code, sizeof(l_code));
// Test br_on_null 2. // Test br_on_null 2.
WasmFunctionBuilder* m = builder->AddFunction(sigs.i_v());
uint32_t m_field_index = 0; uint32_t m_field_index = 0;
m->builder()->AddExport(CStrVector("m"), m); tester.DefineFunction(
byte m_code[] = { "m", tester.sigs.i_v(), {},
WASM_BLOCK_I( {WASM_BLOCK_I(
WASM_I32V(42), WASM_I32V(42),
WASM_STRUCT_GET( WASM_STRUCT_GET(
type_index, m_field_index, type_index, m_field_index,
...@@ -128,20 +224,18 @@ WASM_EXEC_TEST(BasicStruct) { ...@@ -128,20 +224,18 @@ WASM_EXEC_TEST(BasicStruct) {
WASM_BR_ON_NULL(0, WASM_STRUCT_NEW(type_index, WASM_I32V(52), WASM_BR_ON_NULL(0, WASM_STRUCT_NEW(type_index, WASM_I32V(52),
WASM_I32V(62)))), WASM_I32V(62)))),
WASM_BR(0)), WASM_BR(0)),
kExprEnd}; kExprEnd});
m->EmitCode(m_code, sizeof(m_code));
// Test ref.eq // Test ref.eq
WasmFunctionBuilder* n = builder->AddFunction(sigs.i_v()); uint32_t n_local_index = 0;
uint32_t n_local_index = n->AddLocal(kOptRefType); tester.DefineFunction(
n->builder()->AddExport(CStrVector("n"), n); "n", tester.sigs.i_v(), {kOptRefType},
byte n_code[] = { {WASM_SET_LOCAL(n_local_index, WASM_STRUCT_NEW(type_index, WASM_I32V(55),
WASM_SET_LOCAL(n_local_index, WASM_I32V(66))),
WASM_STRUCT_NEW(type_index, WASM_I32V(55), WASM_I32V(66))),
WASM_I32_ADD( WASM_I32_ADD(
WASM_I32_SHL( WASM_I32_SHL(WASM_REF_EQ( // true
WASM_REF_EQ( // true WASM_GET_LOCAL(n_local_index),
WASM_GET_LOCAL(n_local_index), WASM_GET_LOCAL(n_local_index)), WASM_GET_LOCAL(n_local_index)),
WASM_I32V(0)), WASM_I32V(0)),
WASM_I32_ADD( WASM_I32_ADD(
WASM_I32_SHL(WASM_REF_EQ( // false WASM_I32_SHL(WASM_REF_EQ( // false
...@@ -157,257 +251,122 @@ WASM_EXEC_TEST(BasicStruct) { ...@@ -157,257 +251,122 @@ WASM_EXEC_TEST(BasicStruct) {
WASM_REF_NULL_GC(type_index), WASM_REF_NULL_GC(type_index),
WASM_REF_NULL_GC(type_index)), WASM_REF_NULL_GC(type_index)),
WASM_I32V(3))))), WASM_I32V(3))))),
kExprEnd}; kExprEnd});
n->EmitCode(n_code, sizeof(n_code));
// Result: 0b1001 // Result: 0b1001
/************************* End of test definitions *************************/ /************************* End of test definitions *************************/
ZoneBuffer buffer(&zone); tester.CompileModule();
builder->WriteTo(&buffer);
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
testing::SetupIsolateForWasmModule(isolate);
ErrorThrower thrower(isolate, "Test");
MaybeHandle<WasmInstanceObject> maybe_instance =
testing::CompileAndInstantiateForTesting(
isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
if (thrower.error()) FATAL("%s", thrower.error_msg());
Handle<WasmInstanceObject> instance = maybe_instance.ToHandleChecked();
CHECK_EQ(42, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"f", 0, nullptr));
CHECK_EQ(64, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"g", 0, nullptr));
// TODO(7748): This uses the JavaScript interface to retrieve the plain
// WasmStruct. Once the JS interaction story is settled, this may well
// need to be changed.
Handle<WasmExportedFunction> h_export =
testing::GetExportedFunction(isolate, instance, "h").ToHandleChecked();
Handle<Object> undefined = isolate->factory()->undefined_value();
Handle<Object> ref_result =
Execution::Call(isolate, h_export, undefined, 0, nullptr)
.ToHandleChecked();
CHECK(ref_result->IsWasmStruct());
CHECK_EQ(-99, testing::CallWasmFunctionForTesting(isolate, instance, &thrower, tester.CheckResult("f", 42, {});
"j", 0, nullptr)); tester.CheckResult("g", 64, {});
CHECK_EQ(55, testing::CallWasmFunctionForTesting(isolate, instance, &thrower, CHECK(tester.GetJSResult("h", {}).ToHandleChecked()->IsWasmStruct());
"k", 0, nullptr)); tester.CheckResult("j", -99, {});
tester.CheckResult("k", 55, {});
CHECK_EQ(42, testing::CallWasmFunctionForTesting(isolate, instance, &thrower, tester.CheckResult("l", 42, {});
"l", 0, nullptr)); tester.CheckResult("m", 52, {});
tester.CheckResult("n", 0b1001, {});
CHECK_EQ(52, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"m", 0, nullptr));
CHECK_EQ(0b1001, testing::CallWasmFunctionForTesting(
isolate, instance, &thrower, "n", 0, nullptr));
} }
WASM_EXEC_TEST(LetInstruction) { TEST(WasmLetInstruction) {
// TODO(7748): Implement support in other tiers. WasmGCTester tester;
if (execution_tier == ExecutionTier::kLiftoff) return; uint32_t type_index =
if (execution_tier == ExecutionTier::kInterpreter) return; tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
TestSignatures sigs;
EXPERIMENTAL_FLAG_SCOPE(gc);
EXPERIMENTAL_FLAG_SCOPE(typed_funcref);
EXPERIMENTAL_FLAG_SCOPE(anyref);
v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME);
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
StructType::Builder type_builder(&zone, 2);
type_builder.AddField(kWasmI32, true);
type_builder.AddField(kWasmI32, true);
int32_t type_index = builder->AddStructType(type_builder.Build());
ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)};
FunctionSig sig_q_v(1, 0, kRefTypes);
WasmFunctionBuilder* let_test_1 = builder->AddFunction(sigs.i_v());
let_test_1->builder()->AddExport(CStrVector("let_test_1"), let_test_1);
uint32_t let_local_index = 0; uint32_t let_local_index = 0;
uint32_t let_field_index = 0; uint32_t let_field_index = 0;
byte let_code[] = { tester.DefineFunction(
WASM_LET_1_I(WASM_REF_TYPE(type_index), "let_test_1", tester.sigs.i_v(), {},
{WASM_LET_1_I(WASM_REF_TYPE(type_index),
WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(52)), WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(52)),
WASM_STRUCT_GET(type_index, let_field_index, WASM_STRUCT_GET(type_index, let_field_index,
WASM_GET_LOCAL(let_local_index))), WASM_GET_LOCAL(let_local_index))),
kExprEnd}; kExprEnd});
let_test_1->EmitCode(let_code, sizeof(let_code));
WasmFunctionBuilder* let_test_2 = builder->AddFunction(sigs.i_v());
let_test_2->builder()->AddExport(CStrVector("let_test_2"), let_test_2);
uint32_t let_2_field_index = 0; uint32_t let_2_field_index = 0;
byte let_code_2[] = { tester.DefineFunction(
WASM_LET_2_I(kLocalI32, WASM_I32_ADD(WASM_I32V(42), WASM_I32V(-32)), "let_test_2", tester.sigs.i_v(), {},
{WASM_LET_2_I(kLocalI32, WASM_I32_ADD(WASM_I32V(42), WASM_I32V(-32)),
WASM_REF_TYPE(type_index), WASM_REF_TYPE(type_index),
WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(52)), WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(52)),
WASM_I32_MUL(WASM_STRUCT_GET(type_index, let_2_field_index, WASM_I32_MUL(WASM_STRUCT_GET(type_index, let_2_field_index,
WASM_GET_LOCAL(1)), WASM_GET_LOCAL(1)),
WASM_GET_LOCAL(0))), WASM_GET_LOCAL(0))),
kExprEnd}; kExprEnd});
let_test_2->EmitCode(let_code_2, sizeof(let_code_2));
tester.DefineFunction(
WasmFunctionBuilder* let_test_locals = builder->AddFunction(sigs.i_i()); "let_test_locals", tester.sigs.i_i(), {kWasmI32},
let_test_locals->builder()->AddExport(CStrVector("let_test_locals"), {WASM_SET_LOCAL(1, WASM_I32V(100)),
let_test_locals);
let_test_locals->AddLocal(kWasmI32);
byte let_code_locals[] = {
WASM_SET_LOCAL(1, WASM_I32V(100)),
WASM_LET_2_I( WASM_LET_2_I(
kLocalI32, WASM_I32V(1), kLocalI32, WASM_I32V(10), kLocalI32, WASM_I32V(1), kLocalI32, WASM_I32V(10),
WASM_I32_SUB(WASM_I32_ADD(WASM_GET_LOCAL(0), // 1st let-local WASM_I32_SUB(WASM_I32_ADD(WASM_GET_LOCAL(0), // 1st let-local
WASM_GET_LOCAL(2)), // Parameter WASM_GET_LOCAL(2)), // Parameter
WASM_I32_ADD(WASM_GET_LOCAL(1), // 2nd let-local WASM_I32_ADD(WASM_GET_LOCAL(1), // 2nd let-local
WASM_GET_LOCAL(3)))), // Function local WASM_GET_LOCAL(3)))), // Function local
kExprEnd}; kExprEnd});
// Result: (1 + 1000) - (10 + 100) = 891 // Result: (1 + 1000) - (10 + 100) = 891
let_test_locals->EmitCode(let_code_locals, sizeof(let_code_locals));
WasmFunctionBuilder* let_test_erase = builder->AddFunction(sigs.i_v()); uint32_t let_erase_local_index = 0;
let_test_erase->builder()->AddExport(CStrVector("let_test_erase"), tester.DefineFunction("let_test_erase", tester.sigs.i_v(), {kWasmI32},
let_test_erase); {WASM_SET_LOCAL(let_erase_local_index, WASM_I32V(0)),
uint32_t let_erase_local_index = let_test_erase->AddLocal(kWasmI32);
byte let_code_erase[] = {WASM_SET_LOCAL(let_erase_local_index, WASM_I32V(0)),
WASM_LET_1_V(kLocalI32, WASM_I32V(1), WASM_NOP), WASM_LET_1_V(kLocalI32, WASM_I32V(1), WASM_NOP),
WASM_GET_LOCAL(let_erase_local_index), kExprEnd}; WASM_GET_LOCAL(let_erase_local_index), kExprEnd});
// The result should be 0 and not 1, as local_get(0) refers to the original // The result should be 0 and not 1, as local_get(0) refers to the original
// local. // local.
let_test_erase->EmitCode(let_code_erase, sizeof(let_code_erase));
/************************* End of test definitions *************************/
ZoneBuffer buffer(&zone); tester.CompileModule();
builder->WriteTo(&buffer);
Isolate* isolate = CcTest::InitIsolateOnce(); tester.CheckResult("let_test_1", 42, {});
HandleScope scope(isolate); tester.CheckResult("let_test_2", 420, {});
testing::SetupIsolateForWasmModule(isolate); tester.CheckResult("let_test_locals", 891, {Smi::FromInt(1000)});
ErrorThrower thrower(isolate, "Test"); tester.CheckResult("let_test_erase", 0, {});
MaybeHandle<WasmInstanceObject> maybe_instance =
testing::CompileAndInstantiateForTesting(
isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
if (thrower.error()) FATAL("%s", thrower.error_msg());
Handle<WasmInstanceObject> instance = maybe_instance.ToHandleChecked();
CHECK_EQ(42, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"let_test_1", 0, nullptr));
CHECK_EQ(420, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"let_test_2", 0, nullptr));
Handle<Object> let_local_args[] = {handle(Smi::FromInt(1000), isolate)};
CHECK_EQ(891, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"let_test_locals", 1,
let_local_args));
CHECK_EQ(0, testing::CallWasmFunctionForTesting(
isolate, instance, &thrower, "let_test_erase", 0, nullptr));
} }
WASM_EXEC_TEST(BasicArray) { TEST(WasmBasicArray) {
// TODO(7748): Implement support in other tiers. WasmGCTester tester;
if (execution_tier == ExecutionTier::kLiftoff) return; uint32_t type_index = tester.DefineArray(wasm::kWasmI32, true);
if (execution_tier == ExecutionTier::kInterpreter) return;
TestSignatures sigs;
EXPERIMENTAL_FLAG_SCOPE(gc);
EXPERIMENTAL_FLAG_SCOPE(anyref);
v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME);
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
ArrayType type(wasm::kWasmI32, true);
int32_t type_index = builder->AddArrayType(&type);
ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)}; ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)};
FunctionSig sig_q_v(1, 0, kRefTypes); FunctionSig sig_q_v(1, 0, kRefTypes);
ValueType kOptRefType = ValueType(ValueType::kOptRef, type_index); ValueType kOptRefType = ValueType(ValueType::kOptRef, type_index);
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
uint32_t local_index = f->AddLocal(kOptRefType);
f->builder()->AddExport(CStrVector("f"), f);
// f: a = [12, 12, 12]; a[1] = 42; return a[arg0] // f: a = [12, 12, 12]; a[1] = 42; return a[arg0]
byte f_code[] = { uint32_t local_index = 1;
WASM_SET_LOCAL(local_index, tester.DefineFunction(
"f", tester.sigs.i_i(), {kOptRefType},
{WASM_SET_LOCAL(local_index,
WASM_ARRAY_NEW(type_index, WASM_I32V(12), WASM_I32V(3))), WASM_ARRAY_NEW(type_index, WASM_I32V(12), WASM_I32V(3))),
WASM_ARRAY_SET(type_index, WASM_GET_LOCAL(local_index), WASM_I32V(1), WASM_ARRAY_SET(type_index, WASM_GET_LOCAL(local_index), WASM_I32V(1),
WASM_I32V(42)), WASM_I32V(42)),
WASM_ARRAY_GET(type_index, WASM_GET_LOCAL(local_index), WASM_ARRAY_GET(type_index, WASM_GET_LOCAL(local_index),
WASM_GET_LOCAL(0)), WASM_GET_LOCAL(0)),
kExprEnd}; kExprEnd});
f->EmitCode(f_code, sizeof(f_code));
// Reads and returns an array's length. // Reads and returns an array's length.
WasmFunctionBuilder* g = builder->AddFunction(sigs.i_v()); tester.DefineFunction(
f->builder()->AddExport(CStrVector("g"), g); "g", tester.sigs.i_v(), {},
byte g_code[] = { {WASM_ARRAY_LEN(type_index,
WASM_ARRAY_LEN(type_index,
WASM_ARRAY_NEW(type_index, WASM_I32V(0), WASM_I32V(42))), WASM_ARRAY_NEW(type_index, WASM_I32V(0), WASM_I32V(42))),
kExprEnd}; kExprEnd});
g->EmitCode(g_code, sizeof(g_code));
WasmFunctionBuilder* h = builder->AddFunction(&sig_q_v);
h->builder()->AddExport(CStrVector("h"), h);
// Create an array of length 2, initialized to [42, 42]. // Create an array of length 2, initialized to [42, 42].
byte h_code[] = {WASM_ARRAY_NEW(type_index, WASM_I32V(42), WASM_I32V(2)), tester.DefineFunction(
kExprEnd}; "h", &sig_q_v, {},
h->EmitCode(h_code, sizeof(h_code)); {WASM_ARRAY_NEW(type_index, WASM_I32V(42), WASM_I32V(2)), kExprEnd});
ZoneBuffer buffer(&zone); tester.CompileModule();
builder->WriteTo(&buffer);
Isolate* isolate = CcTest::InitIsolateOnce(); tester.CheckResult("f", 12, {Smi::FromInt(0)});
HandleScope scope(isolate); tester.CheckResult("f", 42, {Smi::FromInt(1)});
testing::SetupIsolateForWasmModule(isolate); tester.CheckResult("f", 12, {Smi::FromInt(2)});
ErrorThrower thrower(isolate, "Test"); tester.CheckHasThrown("f", {Smi::FromInt(3)});
Handle<WasmInstanceObject> instance = tester.CheckHasThrown("f", {Smi::FromInt(-1)});
testing::CompileAndInstantiateForTesting( tester.CheckResult("g", 42, {});
isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
.ToHandleChecked();
Handle<Object> argv[] = {handle(Smi::FromInt(0), isolate)};
CHECK_EQ(12, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"f", 1, argv));
argv[0] = handle(Smi::FromInt(1), isolate);
CHECK_EQ(42, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"f", 1, argv));
argv[0] = handle(Smi::FromInt(2), isolate);
CHECK_EQ(12, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"f", 1, argv));
Handle<Object> undefined = isolate->factory()->undefined_value();
{
Handle<WasmExportedFunction> f_export =
testing::GetExportedFunction(isolate, instance, "f").ToHandleChecked();
TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
argv[0] = handle(Smi::FromInt(3), isolate);
MaybeHandle<Object> no_result =
Execution::Call(isolate, f_export, undefined, 1, argv);
CHECK(no_result.is_null());
CHECK(try_catch.HasCaught());
isolate->clear_pending_exception();
argv[0] = handle(Smi::FromInt(-1), isolate);
no_result = Execution::Call(isolate, f_export, undefined, 1, argv);
CHECK(no_result.is_null());
CHECK(try_catch.HasCaught());
isolate->clear_pending_exception();
}
CHECK_EQ(42, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
"g", 0, nullptr));
// TODO(7748): This uses the JavaScript interface to retrieve the plain MaybeHandle<Object> h_result = tester.GetJSResult("h", {});
// WasmArray. Once the JS interaction story is settled, this may well CHECK(h_result.ToHandleChecked()->IsWasmArray());
// need to be changed.
Handle<WasmExportedFunction> h_export =
testing::GetExportedFunction(isolate, instance, "h").ToHandleChecked();
Handle<Object> ref_result =
Execution::Call(isolate, h_export, undefined, 0, nullptr)
.ToHandleChecked();
CHECK(ref_result->IsWasmArray());
#if OBJECT_PRINT #if OBJECT_PRINT
ref_result->Print(); h_result.ToHandleChecked()->Print();
#endif #endif
} }
......
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