Skip to content

Commit c66f220

Browse files
jakobkummerowCommit Bot
authored andcommitted
[wasm-gc] Add a basic test case for structs
Bug: v8:7748 Change-Id: I80265c7070dc7ec421bf53aa717a727c144b0699 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2152844 Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#67288}
1 parent 050a7e0 commit c66f220

10 files changed

Lines changed: 190 additions & 26 deletions

File tree

src/compiler/wasm-compiler.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5382,8 +5382,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
53825382
case wasm::ValueType::kRef:
53835383
case wasm::ValueType::kOptRef:
53845384
case wasm::ValueType::kEqRef:
5385-
// TODO(7748): Implement
5386-
UNIMPLEMENTED();
5385+
// TODO(7748): Implement properly. For now, we just expose the raw
5386+
// object for testing.
5387+
return node;
53875388
case wasm::ValueType::kStmt:
53885389
case wasm::ValueType::kBottom:
53895390
UNREACHABLE();

src/wasm/function-body-decoder-impl.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2887,15 +2887,17 @@ class WasmFullDecoder : public WasmDecoder<validate> {
28872887
len += imm.length;
28882888
if (!this->Validate(this->pc_, imm)) break;
28892889
auto args = PopArgs(imm.struct_type);
2890-
auto* value = Push(ValueType(ValueType::kEqRef, imm.index));
2890+
auto* value = Push(ValueType(ValueType::kRef, imm.index));
28912891
CALL_INTERFACE_IF_REACHABLE(StructNew, imm, args.begin(), value);
28922892
break;
28932893
}
28942894
case kExprStructGet: {
28952895
FieldIndexImmediate<validate> field(this, this->pc_ + len);
28962896
if (!this->Validate(this->pc_ + len, field)) break;
28972897
len += field.length;
2898-
auto struct_obj = Pop(0, kWasmEqRef);
2898+
// TODO(7748): This should take an optref, and perform a null-check.
2899+
auto struct_obj =
2900+
Pop(0, ValueType(ValueType::kRef, field.struct_index.index));
28992901
auto* value = Push(field.struct_index.struct_type->field(field.index));
29002902
CALL_INTERFACE_IF_REACHABLE(StructGet, struct_obj, field, value);
29012903
break;

src/wasm/module-decoder.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,11 +1744,15 @@ class ModuleDecoderImpl : public Decoder {
17441744
if (enabled_features_.has_eh()) return kWasmExnRef;
17451745
break;
17461746
case kLocalRef:
1747-
if (enabled_features_.has_gc()) return ValueType(ValueType::kRef);
1747+
if (enabled_features_.has_gc()) {
1748+
uint32_t type_index = consume_u32v("type index");
1749+
return ValueType(ValueType::kRef, type_index);
1750+
}
17481751
break;
17491752
case kLocalOptRef:
17501753
if (enabled_features_.has_gc()) {
1751-
return ValueType(ValueType::kOptRef);
1754+
uint32_t type_index = consume_u32v("type index");
1755+
return ValueType(ValueType::kOptRef, type_index);
17521756
}
17531757
break;
17541758
case kLocalEqRef:

src/wasm/wasm-module-builder.cc

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ void WasmFunctionBuilder::WriteAsmWasmOffsetTable(ZoneBuffer* buffer) const {
239239

240240
WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
241241
: zone_(zone),
242-
signatures_(zone),
242+
types_(zone),
243243
function_imports_(zone),
244244
global_imports_(zone),
245245
exports_(zone),
@@ -274,9 +274,15 @@ void WasmModuleBuilder::AddDataSegment(const byte* data, uint32_t size,
274274
uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
275275
auto sig_entry = signature_map_.find(*sig);
276276
if (sig_entry != signature_map_.end()) return sig_entry->second;
277-
uint32_t index = static_cast<uint32_t>(signatures_.size());
277+
uint32_t index = static_cast<uint32_t>(types_.size());
278278
signature_map_.emplace(*sig, index);
279-
signatures_.push_back(sig);
279+
types_.push_back(Type(sig));
280+
return index;
281+
}
282+
283+
uint32_t WasmModuleBuilder::AddStructType(StructType* type) {
284+
uint32_t index = static_cast<uint32_t>(types_.size());
285+
types_.push_back(Type(type));
280286
return index;
281287
}
282288

@@ -399,25 +405,50 @@ void WasmModuleBuilder::SetMaxMemorySize(uint32_t value) {
399405

400406
void WasmModuleBuilder::SetHasSharedMemory() { has_shared_memory_ = true; }
401407

408+
namespace {
409+
void WriteValueType(ZoneBuffer* buffer, const ValueType& type) {
410+
buffer->write_u8(type.value_type_code());
411+
if (type.kind() == ValueType::kRef || type.kind() == ValueType::kOptRef) {
412+
buffer->write_u32v(type.ref_index());
413+
}
414+
}
415+
416+
} // namespace
417+
402418
void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
403419
// == Emit magic =============================================================
404420
buffer->write_u32(kWasmMagic);
405421
buffer->write_u32(kWasmVersion);
406422

407-
// == Emit signatures ========================================================
408-
if (signatures_.size() > 0) {
423+
// == Emit types =============================================================
424+
if (types_.size() > 0) {
409425
size_t start = EmitSection(kTypeSectionCode, buffer);
410-
buffer->write_size(signatures_.size());
411-
412-
for (FunctionSig* sig : signatures_) {
413-
buffer->write_u8(kWasmFunctionTypeCode);
414-
buffer->write_size(sig->parameter_count());
415-
for (auto param : sig->parameters()) {
416-
buffer->write_u8(param.value_type_code());
417-
}
418-
buffer->write_size(sig->return_count());
419-
for (auto ret : sig->returns()) {
420-
buffer->write_u8(ret.value_type_code());
426+
buffer->write_size(types_.size());
427+
428+
for (const Type& type : types_) {
429+
switch (type.kind) {
430+
case Type::kFunctionSig: {
431+
FunctionSig* sig = type.sig;
432+
buffer->write_u8(kWasmFunctionTypeCode);
433+
buffer->write_size(sig->parameter_count());
434+
for (auto param : sig->parameters()) {
435+
WriteValueType(buffer, param);
436+
}
437+
buffer->write_size(sig->return_count());
438+
for (auto ret : sig->returns()) {
439+
WriteValueType(buffer, ret);
440+
}
441+
break;
442+
}
443+
case Type::kStructType: {
444+
StructType* struct_type = type.type;
445+
buffer->write_u8(kWasmStructTypeCode);
446+
buffer->write_size(struct_type->field_count());
447+
for (auto field : struct_type->fields()) {
448+
WriteValueType(buffer, field);
449+
}
450+
break;
451+
}
421452
}
422453
}
423454
FixupSection(buffer, start);

src/wasm/wasm-module-builder.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
241241
bool mutability, Vector<const char> module = {});
242242
void AddDataSegment(const byte* data, uint32_t size, uint32_t dest);
243243
uint32_t AddSignature(FunctionSig* sig);
244+
uint32_t AddStructType(StructType* type);
244245
// In the current implementation, it's supported to have uninitialized slots
245246
// at the beginning and/or end of the indirect function table, as long as
246247
// the filled slots form a contiguous block in the middle.
@@ -268,9 +269,25 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
268269

269270
Zone* zone() { return zone_; }
270271

271-
FunctionSig* GetSignature(uint32_t index) { return signatures_[index]; }
272+
FunctionSig* GetSignature(uint32_t index) {
273+
DCHECK(types_[index].kind == Type::kFunctionSig);
274+
return types_[index].sig;
275+
}
272276

273277
private:
278+
struct Type {
279+
enum Kind { kFunctionSig, kStructType };
280+
explicit Type(FunctionSig* signature)
281+
: kind(kFunctionSig), sig(signature) {}
282+
explicit Type(StructType* struct_type)
283+
: kind(kStructType), type(struct_type) {}
284+
Kind kind;
285+
union {
286+
FunctionSig* sig;
287+
StructType* type;
288+
};
289+
};
290+
274291
struct WasmFunctionImport {
275292
Vector<const char> module;
276293
Vector<const char> name;
@@ -310,7 +327,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
310327

311328
friend class WasmFunctionBuilder;
312329
Zone* zone_;
313-
ZoneVector<FunctionSig*> signatures_;
330+
ZoneVector<Type> types_;
314331
ZoneVector<WasmFunctionImport> function_imports_;
315332
ZoneVector<WasmGlobalImport> global_imports_;
316333
ZoneVector<WasmExport> exports_;
@@ -335,7 +352,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
335352
};
336353

337354
inline FunctionSig* WasmFunctionBuilder::signature() {
338-
return builder_->signatures_[signature_index_];
355+
return builder_->types_[signature_index_].sig;
339356
}
340357

341358
} // namespace wasm

src/wasm/wasm-objects.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1421,7 +1421,7 @@ Handle<Map> WasmInstanceObject::GetOrCreateStructMap(
14211421
const wasm::StructType* type = module->struct_type(struct_index);
14221422

14231423
int inobject_properties = 0;
1424-
DCHECK_LE(kMaxInt - WasmStruct::kHeaderSize, type->total_fields_size());
1424+
DCHECK_LE(type->total_fields_size(), kMaxInt - WasmStruct::kHeaderSize);
14251425
int instance_size =
14261426
WasmStruct::kHeaderSize + static_cast<int>(type->total_fields_size());
14271427
InstanceType instance_type = WASM_STRUCT_TYPE;

test/cctest/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ v8_source_set("cctest_sources") {
275275
"unicode-helpers.h",
276276
"wasm/test-c-wasm-entry.cc",
277277
"wasm/test-compilation-cache.cc",
278+
"wasm/test-gc.cc",
278279
"wasm/test-grow-memory.cc",
279280
"wasm/test-jump-table-assembler.cc",
280281
"wasm/test-liftoff-inspection.cc",

test/cctest/cctest.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@
467467
'test-c-wasm-entry/*': [SKIP],
468468
'test-compilation-cache/*': [SKIP],
469469
'test-jump-table-assembler/*': [SKIP],
470+
'test-gc/*': [SKIP],
470471
'test-grow-memory/*': [SKIP],
471472
'test-run-wasm-64/*': [SKIP],
472473
'test-run-wasm-asmjs/*': [SKIP],

test/cctest/wasm/test-gc.cc

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright 2020 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include <stdint.h>
6+
7+
#include "src/utils/utils.h"
8+
#include "src/utils/vector.h"
9+
#include "src/wasm/module-decoder.h"
10+
#include "src/wasm/struct-types.h"
11+
#include "src/wasm/wasm-engine.h"
12+
#include "src/wasm/wasm-module-builder.h"
13+
#include "src/wasm/wasm-module.h"
14+
#include "src/wasm/wasm-objects-inl.h"
15+
#include "src/wasm/wasm-opcodes.h"
16+
#include "test/cctest/cctest.h"
17+
#include "test/cctest/compiler/value-helper.h"
18+
#include "test/cctest/wasm/wasm-run-utils.h"
19+
#include "test/common/wasm/test-signatures.h"
20+
#include "test/common/wasm/wasm-macro-gen.h"
21+
#include "test/common/wasm/wasm-module-runner.h"
22+
23+
namespace v8 {
24+
namespace internal {
25+
namespace wasm {
26+
namespace test_gc {
27+
28+
WASM_EXEC_TEST(BasicStruct) {
29+
// TODO(7748): Implement support in other tiers.
30+
if (execution_tier == ExecutionTier::kLiftoff) return;
31+
if (execution_tier == ExecutionTier::kInterpreter) return;
32+
TestSignatures sigs;
33+
EXPERIMENTAL_FLAG_SCOPE(gc);
34+
EXPERIMENTAL_FLAG_SCOPE(anyref);
35+
v8::internal::AccountingAllocator allocator;
36+
Zone zone(&allocator, ZONE_NAME);
37+
38+
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
39+
StructType::Builder type_builder(&zone, 2);
40+
type_builder.AddField(kWasmI32);
41+
type_builder.AddField(kWasmI32);
42+
int32_t type_index = builder->AddStructType(type_builder.Build());
43+
ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)};
44+
FunctionSig sig_q_v(1, 0, kRefTypes);
45+
46+
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
47+
f->builder()->AddExport(CStrVector("f"), f);
48+
byte f_code[] = {WASM_STRUCT_GET(type_index, 0,
49+
WASM_STRUCT_NEW(type_index, WASM_I32V(42),
50+
WASM_I32V(64))),
51+
kExprEnd};
52+
f->EmitCode(f_code, sizeof(f_code));
53+
54+
WasmFunctionBuilder* g = builder->AddFunction(sigs.i_v());
55+
g->builder()->AddExport(CStrVector("g"), g);
56+
byte g_code[] = {WASM_STRUCT_GET(type_index, 1,
57+
WASM_STRUCT_NEW(type_index, WASM_I32V(42),
58+
WASM_I32V(64))),
59+
kExprEnd};
60+
g->EmitCode(g_code, sizeof(g_code));
61+
62+
WasmFunctionBuilder* h = builder->AddFunction(&sig_q_v);
63+
h->builder()->AddExport(CStrVector("h"), h);
64+
byte h_code[] = {WASM_STRUCT_NEW(type_index, WASM_I32V(42), WASM_I32V(64)),
65+
kExprEnd};
66+
h->EmitCode(h_code, sizeof(h_code));
67+
68+
ZoneBuffer buffer(&zone);
69+
builder->WriteTo(&buffer);
70+
71+
Isolate* isolate = CcTest::InitIsolateOnce();
72+
HandleScope scope(isolate);
73+
testing::SetupIsolateForWasmModule(isolate);
74+
ErrorThrower thrower(isolate, "Test");
75+
Handle<WasmInstanceObject> instance =
76+
testing::CompileAndInstantiateForTesting(
77+
isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
78+
.ToHandleChecked();
79+
80+
CHECK_EQ(42, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
81+
"f", 0, nullptr));
82+
CHECK_EQ(64, testing::CallWasmFunctionForTesting(isolate, instance, &thrower,
83+
"g", 0, nullptr));
84+
85+
// TODO(7748): This uses the JavaScript interface to retrieve the plain
86+
// WasmStruct. Once the JS interaction story is settled, this may well
87+
// need to be changed.
88+
Handle<WasmExportedFunction> h_export =
89+
testing::GetExportedFunction(isolate, instance, "h").ToHandleChecked();
90+
Handle<Object> undefined = isolate->factory()->undefined_value();
91+
Handle<Object> ref_result =
92+
Execution::Call(isolate, h_export, undefined, 0, nullptr)
93+
.ToHandleChecked();
94+
CHECK(ref_result->IsWasmStruct());
95+
}
96+
97+
} // namespace test_gc
98+
} // namespace wasm
99+
} // namespace internal
100+
} // namespace v8

test/common/wasm/wasm-macro-gen.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,13 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
409409

410410
#define TABLE_ZERO 0
411411

412+
#define WASM_GC_OP(op) kGCPrefix, static_cast<byte>(op)
413+
#define WASM_STRUCT_NEW(index, ...) \
414+
__VA_ARGS__, WASM_GC_OP(kExprStructNew), static_cast<byte>(index)
415+
#define WASM_STRUCT_GET(typeidx, fieldidx, ...) \
416+
__VA_ARGS__, WASM_GC_OP(kExprStructGet), static_cast<byte>(typeidx), \
417+
static_cast<byte>(fieldidx)
418+
412419
// Pass: sig_index, ...args, func_index
413420
#define WASM_CALL_INDIRECT(sig_index, ...) \
414421
__VA_ARGS__, kExprCallIndirect, static_cast<byte>(sig_index), TABLE_ZERO

0 commit comments

Comments
 (0)