Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/cctest/wasm/test-gc.cc')
-rw-r--r--deps/v8/test/cctest/wasm/test-gc.cc311
1 files changed, 311 insertions, 0 deletions
diff --git a/deps/v8/test/cctest/wasm/test-gc.cc b/deps/v8/test/cctest/wasm/test-gc.cc
new file mode 100644
index 00000000000..a2249444b11
--- /dev/null
+++ b/deps/v8/test/cctest/wasm/test-gc.cc
@@ -0,0 +1,311 @@
+// Copyright 2020 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+
+#include "src/utils/utils.h"
+#include "src/utils/vector.h"
+#include "src/wasm/module-decoder.h"
+#include "src/wasm/struct-types.h"
+#include "src/wasm/wasm-engine.h"
+#include "src/wasm/wasm-module-builder.h"
+#include "src/wasm/wasm-module.h"
+#include "src/wasm/wasm-objects-inl.h"
+#include "src/wasm/wasm-opcodes.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/compiler/value-helper.h"
+#include "test/cctest/wasm/wasm-run-utils.h"
+#include "test/common/wasm/test-signatures.h"
+#include "test/common/wasm/wasm-macro-gen.h"
+#include "test/common/wasm/wasm-module-runner.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+namespace test_gc {
+
+WASM_EXEC_TEST(BasicStruct) {
+ // TODO(7748): Implement support in other tiers.
+ if (execution_tier == ExecutionTier::kLiftoff) return;
+ 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);
+ StructType::Builder type_builder(&zone, 2);
+ type_builder.AddField(kWasmI32);
+ type_builder.AddField(kWasmI32);
+ int32_t type_index = builder->AddStructType(type_builder.Build());
+ ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)};
+ ValueType kOptRefType = ValueType(ValueType::kOptRef, type_index);
+ FunctionSig sig_q_v(1, 0, kRefTypes);
+
+ // Test struct.new and struct.get.
+ WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
+ f->builder()->AddExport(CStrVector("f"), f);
+ byte f_code[] = {WASM_STRUCT_GET(type_index, 0,
+ WASM_STRUCT_NEW(type_index, WASM_I32V(42),
+ WASM_I32V(64))),
+ kExprEnd};
+ f->EmitCode(f_code, sizeof(f_code));
+
+ // Test struct.new and struct.get.
+ WasmFunctionBuilder* g = builder->AddFunction(sigs.i_v());
+ g->builder()->AddExport(CStrVector("g"), g);
+ byte g_code[] = {WASM_STRUCT_GET(type_index, 1,
+ WASM_STRUCT_NEW(type_index, WASM_I32V(42),
+ WASM_I32V(64))),
+ kExprEnd};
+ g->EmitCode(g_code, sizeof(g_code));
+
+ // Test struct.new, returning struct references to JS.
+ WasmFunctionBuilder* h = builder->AddFunction(&sig_q_v);
+ h->builder()->AddExport(CStrVector("h"), h);
+ byte h_code[] = {WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(64)),
+ kExprEnd};
+ h->EmitCode(h_code, sizeof(h_code));
+
+ // Test struct.set, struct refs types in locals.
+ WasmFunctionBuilder* j = builder->AddFunction(sigs.i_v());
+ uint32_t j_local_index = j->AddLocal(kOptRefType);
+ uint32_t j_field_index = 0;
+ j->builder()->AddExport(CStrVector("j"), j);
+ byte j_code[] = {
+ WASM_SET_LOCAL(j_local_index,
+ WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(64))),
+ WASM_STRUCT_SET(type_index, j_field_index, WASM_GET_LOCAL(j_local_index),
+ WASM_I32V(-99)),
+ WASM_STRUCT_GET(type_index, j_field_index, WASM_GET_LOCAL(j_local_index)),
+ kExprEnd};
+ j->EmitCode(j_code, sizeof(j_code));
+
+ // Test struct.set, ref.as_non_null,
+ // struct refs types in globals and if-results.
+ uint32_t k_global_index = builder->AddGlobal(kOptRefType, true);
+ WasmFunctionBuilder* k = builder->AddFunction(sigs.i_v());
+ uint32_t k_field_index = 0;
+ k->builder()->AddExport(CStrVector("k"), k);
+ byte k_code[] = {
+ WASM_SET_GLOBAL(k_global_index, WASM_STRUCT_NEW(type_index, WASM_I32V(55),
+ WASM_I32V(66))),
+ WASM_STRUCT_GET(type_index, k_field_index,
+ WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(
+ kOptRefType, WASM_I32V(1),
+ WASM_GET_GLOBAL(k_global_index), WASM_REF_NULL))),
+ kExprEnd};
+ k->EmitCode(k_code, sizeof(k_code));
+
+ // Test br_on_null 1.
+ WasmFunctionBuilder* l = builder->AddFunction(sigs.i_v());
+ uint32_t l_local_index = l->AddLocal(kOptRefType);
+ l->builder()->AddExport(CStrVector("l"), l);
+ byte l_code[] = {
+ WASM_BLOCK_I(WASM_I32V(42),
+ // Branch will be taken.
+ // 42 left on stack outside the block (not 52).
+ WASM_BR_ON_NULL(0, WASM_GET_LOCAL(l_local_index)),
+ WASM_I32V(52), WASM_BR(0)),
+ kExprEnd};
+ l->EmitCode(l_code, sizeof(l_code));
+
+ // Test br_on_null 2.
+ WasmFunctionBuilder* m = builder->AddFunction(sigs.i_v());
+ uint32_t m_field_index = 0;
+ m->builder()->AddExport(CStrVector("m"), m);
+ byte m_code[] = {
+ WASM_BLOCK_I(
+ WASM_I32V(42),
+ WASM_STRUCT_GET(
+ type_index, m_field_index,
+ // Branch will not be taken.
+ // 52 left on stack outside the block (not 42).
+ WASM_BR_ON_NULL(0, WASM_STRUCT_NEW(type_index, WASM_I32V(52),
+ WASM_I32V(62)))),
+ WASM_BR(0)),
+ kExprEnd};
+ m->EmitCode(m_code, sizeof(m_code));
+
+ // Test ref.eq
+ WasmFunctionBuilder* n = builder->AddFunction(sigs.i_v());
+ uint32_t n_local_index = n->AddLocal(kOptRefType);
+ n->builder()->AddExport(CStrVector("n"), n);
+ byte n_code[] = {
+ WASM_SET_LOCAL(n_local_index,
+ WASM_STRUCT_NEW(type_index, WASM_I32V(55), WASM_I32V(66))),
+ WASM_I32_ADD(
+ WASM_I32_SHL(
+ WASM_REF_EQ( // true
+ WASM_GET_LOCAL(n_local_index), WASM_GET_LOCAL(n_local_index)),
+ WASM_I32V(0)),
+ WASM_I32_ADD(
+ WASM_I32_SHL(WASM_REF_EQ( // false
+ WASM_GET_LOCAL(n_local_index),
+ WASM_STRUCT_NEW(type_index, WASM_I32V(55),
+ WASM_I32V(66))),
+ WASM_I32V(1)),
+ WASM_I32_ADD(
+ WASM_I32_SHL( // false
+ WASM_REF_EQ(WASM_GET_LOCAL(n_local_index), WASM_REF_NULL),
+ WASM_I32V(2)),
+ WASM_I32_SHL(WASM_REF_EQ( // true
+ WASM_REF_NULL, WASM_REF_NULL),
+ WASM_I32V(3))))),
+ kExprEnd};
+ n->EmitCode(n_code, sizeof(n_code));
+ // Result: 0b1001
+
+ ZoneBuffer buffer(&zone);
+ builder->WriteTo(&buffer);
+
+ Isolate* isolate = CcTest::InitIsolateOnce();
+ HandleScope scope(isolate);
+ testing::SetupIsolateForWasmModule(isolate);
+ ErrorThrower thrower(isolate, "Test");
+ Handle<WasmInstanceObject> instance =
+ testing::CompileAndInstantiateForTesting(
+ isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
+ .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,
+ "j", 0, nullptr));
+
+ CHECK_EQ(55, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
+ "k", 0, nullptr));
+
+ CHECK_EQ(42, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
+ "l", 0, nullptr));
+
+ 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(BasicArray) {
+ // TODO(7748): Implement support in other tiers.
+ if (execution_tier == ExecutionTier::kLiftoff) return;
+ 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);
+ int32_t type_index = builder->AddArrayType(&type);
+ ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)};
+ FunctionSig sig_q_v(1, 0, kRefTypes);
+ 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]
+ byte f_code[] = {
+ WASM_SET_LOCAL(local_index,
+ 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_I32V(42)),
+ WASM_ARRAY_GET(type_index, WASM_GET_LOCAL(local_index),
+ WASM_GET_LOCAL(0)),
+ kExprEnd};
+ f->EmitCode(f_code, sizeof(f_code));
+
+ // Reads and returns an array's length.
+ WasmFunctionBuilder* g = builder->AddFunction(sigs.i_v());
+ f->builder()->AddExport(CStrVector("g"), g);
+ byte g_code[] = {
+ WASM_ARRAY_LEN(type_index,
+ WASM_ARRAY_NEW(type_index, WASM_I32V(0), WASM_I32V(42))),
+ 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].
+ byte h_code[] = {WASM_ARRAY_NEW(type_index, WASM_I32V(42), WASM_I32V(2)),
+ kExprEnd};
+ h->EmitCode(h_code, sizeof(h_code));
+
+ ZoneBuffer buffer(&zone);
+ builder->WriteTo(&buffer);
+
+ Isolate* isolate = CcTest::InitIsolateOnce();
+ HandleScope scope(isolate);
+ testing::SetupIsolateForWasmModule(isolate);
+ ErrorThrower thrower(isolate, "Test");
+ Handle<WasmInstanceObject> instance =
+ testing::CompileAndInstantiateForTesting(
+ 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
+ // WasmArray. 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> ref_result =
+ Execution::Call(isolate, h_export, undefined, 0, nullptr)
+ .ToHandleChecked();
+ CHECK(ref_result->IsWasmArray());
+#if OBJECT_PRINT
+ ref_result->Print();
+#endif
+}
+
+} // namespace test_gc
+} // namespace wasm
+} // namespace internal
+} // namespace v8