Commit 37579df7 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm] Complete element segment features for reftypes/typed-funcref

Main changes:
- Allow global.get in elements segments with expressions-as-elements.
- Allow element segments with types other than funcref.

Detailed changes:
- Move WasmInitExpr to its own file. Add stream opearator << support.
- Simplify type of PrintCollection.
- Make WasmElemSegment use an array of WasmInitExpr's over the previous
  ad-hoc implementation. Move null_index to WasmModuleBuilder.
- Refactor consume_element_segment_header. Make it return a
  WasmElemSegment.
- Refactor consume_element_expr. Make it return a WasmInitExpr.
- Refactor DecodeElementSection. Make it invoke
  consume_element_segment_header, then populate its element array.
- Update module-instantiate.cc to handle global.get elements.
- Fix bug in wasm-objects.cc where the wrong type index was passed into
  module()->has_signature()
- Adapt and add tests.

Change-Id: I5abfbe424dbb750ee2dca59f91c451ffcb79f95f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2857959
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74374}
parent 3f28ca94
......@@ -3121,6 +3121,7 @@ v8_header_set("v8_internal_headers") {
"src/wasm/wasm-feature-flags.h",
"src/wasm/wasm-features.h",
"src/wasm/wasm-import-wrapper-cache.h",
"src/wasm/wasm-init-expr.h",
"src/wasm/wasm-js.h",
"src/wasm/wasm-linkage.h",
"src/wasm/wasm-module-builder.h",
......@@ -4057,6 +4058,7 @@ v8_source_set("v8_base_without_compiler") {
"src/wasm/wasm-external-refs.cc",
"src/wasm/wasm-features.cc",
"src/wasm/wasm-import-wrapper-cache.cc",
"src/wasm/wasm-init-expr.cc",
"src/wasm/wasm-js.cc",
"src/wasm/wasm-module-builder.cc",
"src/wasm/wasm-module-sourcemap.cc",
......
......@@ -9,7 +9,6 @@
#include "src/codegen/interface-descriptors.h"
#include "src/objects/objects-inl.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-opcodes.h"
namespace v8 {
namespace internal {
......
......@@ -158,10 +158,10 @@ struct PrintIteratorRange {
// Print any collection which can be iterated via std::begin and std::end.
// {Iterator} is the common type of {std::begin} and {std::end} called on a
// {const T&}. This function is only instantiable if that type exists.
template <typename T, typename Iterator = typename std::common_type<
decltype(std::begin(std::declval<const T&>())),
decltype(std::end(std::declval<const T&>()))>::type>
PrintIteratorRange<Iterator> PrintCollection(const T& collection) {
template <typename T>
auto PrintCollection(const T& collection) -> PrintIteratorRange<
typename std::common_type<decltype(std::begin(collection)),
decltype(std::end(collection))>::type> {
return {std::begin(collection), std::end(collection)};
}
......
......@@ -10,7 +10,6 @@
#define V8_WASM_GRAPH_BUILDER_INTERFACE_H_
#include "src/wasm/decoder.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-result.h"
namespace v8 {
......
......@@ -32,7 +32,6 @@
#include "src/wasm/wasm-js.h"
#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-result.h"
#include "src/wasm/wasm-serialization.h"
......
This diff is collapsed.
......@@ -20,6 +20,7 @@
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-subtyping.h"
#include "src/wasm/wasm-value.h"
#define TRACE(...) \
do { \
......@@ -1907,10 +1908,10 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
const WasmModule* module = instance->module();
for (size_t i = 0; i < count; ++i) {
uint32_t func_index = elem_segment.entries[src + i];
const WasmInitExpr* init = &elem_segment.entries[src + i];
int entry_index = static_cast<int>(dst + i);
if (func_index == WasmElemSegment::kNullIndex) {
if (init->kind() == WasmInitExpr::kRefNullConst) {
if (IsSubtypeOf(table_object->type(), kWasmFuncRef, module)) {
IndirectFunctionTableEntry(instance, table_index, entry_index).clear();
}
......@@ -1919,6 +1920,18 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
continue;
}
if (init->kind() == WasmInitExpr::kGlobalGet) {
WasmTableObject::Set(
isolate, table_object, entry_index,
WasmInstanceObject::GetGlobalValue(
instance, module->globals[init->immediate().index])
.to_ref());
continue;
}
DCHECK_EQ(init->kind(), WasmInitExpr::kRefFuncConst);
const uint32_t func_index = init->immediate().index;
const WasmFunction* function = &module->functions[func_index];
// Update the local dispatch table first if necessary.
......
// Copyright 2021 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 "src/wasm/wasm-init-expr.h"
namespace v8 {
namespace internal {
namespace wasm {
std::ostream& operator<<(std::ostream& os, const WasmInitExpr& expr) {
os << "(";
switch (expr.kind()) {
case WasmInitExpr::kNone:
UNREACHABLE();
case WasmInitExpr::kGlobalGet:
os << "global.get " << expr.immediate().index;
break;
case WasmInitExpr::kI32Const:
os << "i32.const " << expr.immediate().i32_const;
break;
case WasmInitExpr::kI64Const:
os << "i64.const " << expr.immediate().i64_const;
break;
case WasmInitExpr::kF32Const:
os << "f32.const " << expr.immediate().f32_const;
break;
case WasmInitExpr::kF64Const:
os << "f64.const " << expr.immediate().f64_const;
break;
case WasmInitExpr::kS128Const:
os << "s128.const 0x" << std::hex;
for (uint8_t b : expr.immediate().s128_const) {
os << b;
}
os << std::dec;
break;
case WasmInitExpr::kRefNullConst:
os << "ref.null " << expr.immediate().heap_type;
break;
case WasmInitExpr::kRefFuncConst:
os << "ref.func " << expr.immediate().index;
break;
case WasmInitExpr::kRttCanon:
os << "rtt.canon " << expr.immediate().heap_type;
break;
case WasmInitExpr::kRttSub:
os << "rtt.sub " << *expr.operand();
break;
}
os << ")";
return os;
}
} // namespace wasm
} // namespace internal
} // namespace v8
// Copyright 2021 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.
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif // !V8_ENABLE_WEBASSEMBLY
#ifndef V8_WASM_WASM_INIT_EXPR_H_
#define V8_WASM_WASM_INIT_EXPR_H_
#include "src/wasm/value-type.h"
namespace v8 {
namespace internal {
namespace wasm {
// Representation of an initializer expression.
class WasmInitExpr {
public:
enum Operator {
kNone,
kGlobalGet,
kI32Const,
kI64Const,
kF32Const,
kF64Const,
kS128Const,
kRefNullConst,
kRefFuncConst,
kRttCanon,
kRttSub
};
union Immediate {
int32_t i32_const;
int64_t i64_const;
float f32_const;
double f64_const;
std::array<uint8_t, kSimd128Size> s128_const;
uint32_t index;
HeapType::Representation heap_type;
};
WasmInitExpr() : kind_(kNone) { immediate_.i32_const = 0; }
explicit WasmInitExpr(int32_t v) : kind_(kI32Const) {
immediate_.i32_const = v;
}
explicit WasmInitExpr(int64_t v) : kind_(kI64Const) {
immediate_.i64_const = v;
}
explicit WasmInitExpr(float v) : kind_(kF32Const) {
immediate_.f32_const = v;
}
explicit WasmInitExpr(double v) : kind_(kF64Const) {
immediate_.f64_const = v;
}
explicit WasmInitExpr(uint8_t v[kSimd128Size]) : kind_(kS128Const) {
base::Memcpy(immediate_.s128_const.data(), v, kSimd128Size);
}
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmInitExpr);
static WasmInitExpr GlobalGet(uint32_t index) {
WasmInitExpr expr;
expr.kind_ = kGlobalGet;
expr.immediate_.index = index;
return expr;
}
static WasmInitExpr RefFuncConst(uint32_t index) {
WasmInitExpr expr;
expr.kind_ = kRefFuncConst;
expr.immediate_.index = index;
return expr;
}
static WasmInitExpr RefNullConst(HeapType::Representation heap_type) {
WasmInitExpr expr;
expr.kind_ = kRefNullConst;
expr.immediate_.heap_type = heap_type;
return expr;
}
static WasmInitExpr RttCanon(uint32_t index) {
WasmInitExpr expr;
expr.kind_ = kRttCanon;
expr.immediate_.index = index;
return expr;
}
static WasmInitExpr RttSub(uint32_t index, WasmInitExpr supertype) {
WasmInitExpr expr;
expr.kind_ = kRttSub;
expr.immediate_.index = index;
expr.operand_ = std::make_unique<WasmInitExpr>(std::move(supertype));
return expr;
}
Immediate immediate() const { return immediate_; }
Operator kind() const { return kind_; }
WasmInitExpr* operand() const { return operand_.get(); }
bool operator==(const WasmInitExpr& other) const {
if (kind() != other.kind()) return false;
switch (kind()) {
case kNone:
return true;
case kGlobalGet:
case kRefFuncConst:
case kRttCanon:
return immediate().index == other.immediate().index;
case kI32Const:
return immediate().i32_const == other.immediate().i32_const;
case kI64Const:
return immediate().i64_const == other.immediate().i64_const;
case kF32Const:
return immediate().f32_const == other.immediate().f32_const;
case kF64Const:
return immediate().f64_const == other.immediate().f64_const;
case kS128Const:
return immediate().s128_const == other.immediate().s128_const;
case kRefNullConst:
return immediate().heap_type == other.immediate().heap_type;
case kRttSub:
return immediate().index == other.immediate().index &&
*operand() == *other.operand();
}
}
V8_INLINE bool operator!=(const WasmInitExpr& other) {
return !(*this == other);
}
private:
Immediate immediate_;
Operator kind_;
std::unique_ptr<WasmInitExpr> operand_ = nullptr;
};
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const WasmInitExpr& expr);
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_WASM_INIT_EXPR_H_
......@@ -13,7 +13,6 @@
#include "src/wasm/leb-helper.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/zone/zone-containers.h"
namespace v8 {
......@@ -301,6 +300,11 @@ uint32_t WasmModuleBuilder::AddArrayType(ArrayType* type) {
return index;
}
// static
const uint32_t WasmModuleBuilder::kNullIndex =
std::numeric_limits<uint32_t>::max();
// TODO(9495): Add support for typed function tables and more init. expressions.
uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) {
DCHECK(allocating_indirect_functions_allowed_);
uint32_t index = static_cast<uint32_t>(indirect_functions_.size());
......@@ -310,7 +314,7 @@ uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) {
}
uint32_t new_size = static_cast<uint32_t>(indirect_functions_.size()) + count;
DCHECK(max_table_size_ == 0 || new_size <= max_table_size_);
indirect_functions_.resize(new_size, WasmElemSegment::kNullIndex);
indirect_functions_.resize(new_size, kNullIndex);
uint32_t max = max_table_size_ > 0 ? max_table_size_ : new_size;
if (tables_.empty()) {
// This cannot use {AddTable} because that would flip the
......@@ -710,13 +714,13 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
buffer->write_u8(0); // table index
uint32_t first_element = 0;
while (first_element < indirect_functions_.size() &&
indirect_functions_[first_element] == WasmElemSegment::kNullIndex) {
indirect_functions_[first_element] == kNullIndex) {
first_element++;
}
uint32_t last_element =
static_cast<uint32_t>(indirect_functions_.size() - 1);
while (last_element >= first_element &&
indirect_functions_[last_element] == WasmElemSegment::kNullIndex) {
indirect_functions_[last_element] == kNullIndex) {
last_element--;
}
buffer->write_u8(kExprI32Const); // offset
......
......@@ -297,6 +297,8 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
return types_[exceptions_[index]].sig;
}
static const uint32_t kNullIndex;
private:
struct Type {
enum Kind { kFunctionSig, kStructType, kArrayType };
......
......@@ -21,6 +21,7 @@
#include "src/snapshot/snapshot.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-code-manager.h"
#include "src/wasm/wasm-init-expr.h"
#include "src/wasm/wasm-js.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-result.h"
......@@ -30,9 +31,6 @@ namespace v8 {
namespace internal {
namespace wasm {
// static
const uint32_t WasmElemSegment::kNullIndex;
WireBytesRef LazilyGeneratedNames::LookupFunctionName(
const ModuleWireBytes& wire_bytes, uint32_t function_index,
Vector<const WasmExport> export_table) const {
......
......@@ -19,7 +19,7 @@
#include "src/wasm/signature-map.h"
#include "src/wasm/struct-types.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-init-expr.h"
namespace v8 {
......@@ -107,30 +107,34 @@ struct WasmDataSegment {
// Static representation of wasm element segment (table initializer).
struct WasmElemSegment {
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmElemSegment);
// Construct an active segment.
WasmElemSegment(uint32_t table_index, WasmInitExpr offset)
: type(kWasmFuncRef),
WasmElemSegment(ValueType type, uint32_t table_index, WasmInitExpr offset)
: type(type),
table_index(table_index),
offset(std::move(offset)),
status(kStatusActive) {}
// Construct a passive or declarative segment, which has no table index or
// offset.
explicit WasmElemSegment(bool declarative)
: type(kWasmFuncRef),
WasmElemSegment(ValueType type, bool declarative)
: type(type),
table_index(0),
status(declarative ? kStatusDeclarative : kStatusPassive) {}
// Used in the {entries} vector to represent a `ref.null` entry in a passive
// segment.
V8_EXPORT_PRIVATE static const uint32_t kNullIndex = ~0u;
// Construct a passive or declarative segment, which has no table index or
// offset.
WasmElemSegment()
: type(kWasmBottom), table_index(0), status(kStatusActive) {}
WasmElemSegment(const WasmElemSegment&) = delete;
WasmElemSegment(WasmElemSegment&&) V8_NOEXCEPT = default;
WasmElemSegment& operator=(const WasmElemSegment&) = delete;
WasmElemSegment& operator=(WasmElemSegment&&) V8_NOEXCEPT = default;
ValueType type;
uint32_t table_index;
WasmInitExpr offset;
std::vector<uint32_t> entries;
std::vector<WasmInitExpr> entries;
enum Status {
kStatusActive, // copied automatically during instantiation.
kStatusPassive, // copied explicitly after instantiation.
......
......@@ -463,10 +463,9 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
default:
DCHECK(!table->instance().IsUndefined());
// TODO(7748): Relax this once we have struct/array/i31ref tables.
DCHECK_EQ(WasmInstanceObject::cast(table->instance())
.module()
->type_kinds[table->type().ref_index()],
wasm::kWasmFunctionTypeCode);
DCHECK(WasmInstanceObject::cast(table->instance())
.module()
->has_signature(table->type().ref_index()));
SetFunctionTableEntry(isolate, table, entries, entry_index, entry);
return;
}
......@@ -509,18 +508,16 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
UNREACHABLE();
default:
DCHECK(!table->instance().IsUndefined());
if (WasmInstanceObject::cast(table->instance())
.module()
->has_signature(entry_index)) {
if (WasmExportedFunction::IsWasmExportedFunction(*entry) ||
WasmJSFunction::IsWasmJSFunction(*entry) ||
WasmCapiFunction::IsWasmCapiFunction(*entry)) {
return entry;
}
break;
// TODO(7748): Relax this once we have struct/array/i31ref tables.
DCHECK(WasmInstanceObject::cast(table->instance())
.module()
->has_signature(table->type().ref_index()));
if (WasmExportedFunction::IsWasmExportedFunction(*entry) ||
WasmJSFunction::IsWasmJSFunction(*entry) ||
WasmCapiFunction::IsWasmCapiFunction(*entry)) {
return entry;
}
// TODO(7748): Implement once we have a story for struct/arrays in JS.
UNIMPLEMENTED();
break;
}
// {entry} is not a valid entry in the table. It has to be a placeholder
......
......@@ -801,129 +801,6 @@ class V8_EXPORT_PRIVATE WasmOpcodes {
static inline const char* TrapReasonMessage(TrapReason);
};
// Representation of an initializer expression.
class WasmInitExpr {
public:
enum Operator {
kNone,
kGlobalGet,
kI32Const,
kI64Const,
kF32Const,
kF64Const,
kS128Const,
kRefNullConst,
kRefFuncConst,
kRttCanon,
kRttSub
};
union Immediate {
int32_t i32_const;
int64_t i64_const;
float f32_const;
double f64_const;
std::array<uint8_t, kSimd128Size> s128_const;
uint32_t index;
HeapType::Representation heap_type;
};
WasmInitExpr() : kind_(kNone) { immediate_.i32_const = 0; }
explicit WasmInitExpr(int32_t v) : kind_(kI32Const) {
immediate_.i32_const = v;
}
explicit WasmInitExpr(int64_t v) : kind_(kI64Const) {
immediate_.i64_const = v;
}
explicit WasmInitExpr(float v) : kind_(kF32Const) {
immediate_.f32_const = v;
}
explicit WasmInitExpr(double v) : kind_(kF64Const) {
immediate_.f64_const = v;
}
explicit WasmInitExpr(uint8_t v[kSimd128Size]) : kind_(kS128Const) {
base::Memcpy(immediate_.s128_const.data(), v, kSimd128Size);
}
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmInitExpr);
static WasmInitExpr GlobalGet(uint32_t index) {
WasmInitExpr expr;
expr.kind_ = kGlobalGet;
expr.immediate_.index = index;
return expr;
}
static WasmInitExpr RefFuncConst(uint32_t index) {
WasmInitExpr expr;
expr.kind_ = kRefFuncConst;
expr.immediate_.index = index;
return expr;
}
static WasmInitExpr RefNullConst(HeapType::Representation heap_type) {
WasmInitExpr expr;
expr.kind_ = kRefNullConst;
expr.immediate_.heap_type = heap_type;
return expr;
}
static WasmInitExpr RttCanon(uint32_t index) {
WasmInitExpr expr;
expr.kind_ = kRttCanon;
expr.immediate_.index = index;
return expr;
}
static WasmInitExpr RttSub(uint32_t index, WasmInitExpr supertype) {
WasmInitExpr expr;
expr.kind_ = kRttSub;
expr.immediate_.index = index;
expr.operand_ = std::make_unique<WasmInitExpr>(std::move(supertype));
return expr;
}
Immediate immediate() const { return immediate_; }
Operator kind() const { return kind_; }
WasmInitExpr* operand() const { return operand_.get(); }
bool operator==(const WasmInitExpr& other) const {
if (kind() != other.kind()) return false;
switch (kind()) {
case kNone:
return true;
case kGlobalGet:
case kRefFuncConst:
case kRttCanon:
return immediate().index == other.immediate().index;
case kI32Const:
return immediate().i32_const == other.immediate().i32_const;
case kI64Const:
return immediate().i64_const == other.immediate().i64_const;
case kF32Const:
return immediate().f32_const == other.immediate().f32_const;
case kF64Const:
return immediate().f64_const == other.immediate().f64_const;
case kS128Const:
return immediate().s128_const == other.immediate().s128_const;
case kRefNullConst:
return immediate().heap_type == other.immediate().heap_type;
case kRttSub:
return immediate().index == other.immediate().index &&
*operand() == *other.operand();
}
}
V8_INLINE bool operator!=(const WasmInitExpr& other) {
return !(*this == other);
}
private:
Immediate immediate_;
Operator kind_;
std::unique_ptr<WasmInitExpr> operand_ = nullptr;
};
} // namespace wasm
} // namespace internal
} // namespace v8
......
......@@ -12,7 +12,7 @@
#include "src/base/memory.h"
#include "src/handles/handles.h"
#include "src/utils/boxed-float.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/value-type.h"
#include "src/zone/zone-containers.h"
namespace v8 {
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/wasm/wasm-module-builder.h"
#include "test/cctest/cctest.h"
#include "test/cctest/wasm/wasm-run-utils.h"
#include "test/common/wasm/test-signatures.h"
......@@ -413,7 +414,7 @@ void TestTableInitElems(TestExecutionTier execution_tier, int table_index) {
}
// Passive element segment has [f0, f1, f2, f3, f4, null].
function_indexes.push_back(WasmElemSegment::kNullIndex);
function_indexes.push_back(WasmModuleBuilder::kNullIndex);
// Add 10 function tables, even though we only test one table.
for (int i = 0; i < 10; ++i) {
......
......@@ -295,9 +295,11 @@ uint32_t TestingModuleBuilder::AddPassiveElementSegment(
uint32_t index = static_cast<uint32_t>(test_module_->elem_segments.size());
DCHECK_EQ(index, dropped_elem_segments_.size());
test_module_->elem_segments.emplace_back(false);
test_module_->elem_segments.emplace_back(kWasmFuncRef, false);
auto& elem_segment = test_module_->elem_segments.back();
elem_segment.entries = entries;
for (uint32_t entry : entries) {
elem_segment.entries.push_back(WasmInitExpr::RefFuncConst(entry));
}
// The vector pointers may have moved, so update the instance object.
dropped_elem_segments_.push_back(0);
......
// Copyright 2021 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.
// Flags: --experimental-wasm-typed-funcref
load('test/mjsunit/wasm/wasm-module-builder.js');
(function TestGlobalGetElement() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let table = builder.addTable(kWasmFuncRef, 10, 10).exportAs('table');
let f0 = builder.addFunction('double', kSig_i_i).addBody([
kExprLocalGet, 0, kExprLocalGet, 0, kExprI32Add
]);
let f1 = builder.addFunction('inc', kSig_i_i).addBody([
kExprLocalGet, 0, kExprI32Const, 1, kExprI32Add
]);
let global0 =
builder.addGlobal(kWasmFuncRef, false, WasmInitExpr.RefFunc(f0.index));
let global1 =
builder.addGlobal(kWasmFuncRef, false, WasmInitExpr.RefFunc(f1.index));
// At instantiation, table[0] = global0, table[1] = global1.
builder.addActiveElementSegment(
table.index, WasmInitExpr.I32Const(0),
[
WasmInitExpr.GlobalGet(global0.index),
WasmInitExpr.GlobalGet(global1.index)
],
kWasmFuncRef);
let passive = builder.addPassiveElementSegment(
[
WasmInitExpr.GlobalGet(global0.index),
WasmInitExpr.GlobalGet(global1.index)
],
kWasmFuncRef);
// table[2] = global0, table[3] = global1.
builder.addFunction('init', kSig_v_v)
.addBody([
kExprI32Const, 2, // table index
kExprI32Const, 0, // element index
kExprI32Const, 2, // length
kNumericPrefix, kExprTableInit, passive, table.index
])
.exportFunc();
let instance = builder.instantiate({});
instance.exports.init();
assertEquals(instance.exports.table.get(0)(10), 20);
assertEquals(instance.exports.table.get(1)(10), 11);
assertEquals(instance.exports.table.get(2)(10), 20);
assertEquals(instance.exports.table.get(3)(10), 11);
})();
(function TestTypedFunctionElementSegment() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig = builder.addType(kSig_i_i);
let f0 = builder.addFunction('double', sig).addBody([
kExprLocalGet, 0, kExprLocalGet, 0, kExprI32Add
]);
let f1 = builder.addFunction('inc', sig).addBody([
kExprLocalGet, 0, kExprI32Const, 1, kExprI32Add
]);
let table =
builder.addTable(wasmRefType(sig), 10, 10, WasmInitExpr.RefFunc(f0.index))
.exportAs('table');
builder.addActiveElementSegment(
table.index, WasmInitExpr.I32Const(0),
[WasmInitExpr.RefFunc(f0.index), WasmInitExpr.RefFunc(f1.index)],
wasmRefType(sig));
let passive = builder.addPassiveElementSegment(
[WasmInitExpr.RefFunc(f0.index), WasmInitExpr.RefFunc(f1.index)],
wasmRefType(sig));
builder.addFunction('init', kSig_v_v)
.addBody([
kExprI32Const, 2, // table index
kExprI32Const, 0, // element index
kExprI32Const, 2, // length
kNumericPrefix, kExprTableInit, passive, table.index
])
.exportFunc();
let instance = builder.instantiate({});
instance.exports.init();
assertEquals(instance.exports.table.get(0)(10), 20);
assertEquals(instance.exports.table.get(1)(10), 11);
assertEquals(instance.exports.table.get(2)(10), 20);
assertEquals(instance.exports.table.get(3)(10), 11);
})();
......@@ -158,19 +158,20 @@ class TestModuleBuilder {
}
byte AddPassiveElementSegment(wasm::ValueType type) {
mod.elem_segments.emplace_back(false);
mod.elem_segments.emplace_back(type, false);
auto& init = mod.elem_segments.back();
init.type = type;
// Add 5 empty elements.
for (uint32_t j = 0; j < 5; j++) {
init.entries.push_back(WasmElemSegment::kNullIndex);
init.entries.push_back(
WasmInitExpr::RefNullConst(type.heap_representation()));
}
return static_cast<byte>(mod.elem_segments.size() - 1);
}
byte AddDeclarativeElementSegment() {
mod.elem_segments.emplace_back(true);
mod.elem_segments.back().entries.push_back(WasmElemSegment::kNullIndex);
mod.elem_segments.emplace_back(kWasmFuncRef, true);
mod.elem_segments.back().entries.push_back(
WasmInitExpr::RefNullConst(HeapType::kFunc));
return static_cast<byte>(mod.elem_segments.size() - 1);
}
......
......@@ -1848,8 +1848,10 @@ TEST_F(WasmModuleVerifyTest, ElementSectionInitExternRefTableWithFuncRef) {
ONE_EMPTY_BODY,
};
EXPECT_FAILURE_WITH_MSG(
data, "Invalid element segment. Table 0 is not a super-type of funcref");
EXPECT_FAILURE_WITH_MSG(data,
"An active element segment with function indices as "
"elements must reference a table of type funcref. "
"Instead, table 0 of type externref is referenced.");
}
TEST_F(WasmModuleVerifyTest, ElementSectionDontInitExternRefImportedTable) {
......
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