Commit 5756c40e authored by Clemens Backes's avatar Clemens Backes Committed by V8 LUCI CQ

Revert "[wasm] Refactor initializer expression handling"

This reverts commit 071a1acf.

Reason for revert: Breaks on nosse: https://ci.chromium.org/ui/p/v8/builders/ci/V8%20Linux/42795/overview

Original change's description:
> [wasm] Refactor initializer expression handling
>
> Design doc: https://bit.ly/3xPxWUe
>
> This CL introduces two main changes:
> - Initializer expressions are now decoded by WasmFullDecoder. With
>   wasm-gc, initializer expressions are no longer just constants, and
>   require complex decoding (including stack tracking). This resulted in
>   extensive code duplication.
> - Initializer expressions are not stored explicitly by module-decoder as
>   an AST (WasmInitExpr), but rather as a WireBytesRef, and are decoded
>   again during module instantiation. This should reduce memory
>   consumption for globals and other module elements with initializer
>   expressions (which has been observed in the 40MB range in some
>   real-world benchmarks.
>
> Summary of changes:
> - Add a static parameter {kFunctionBody, kInitExpression} to the
>   WasmDecoder. Use it to specialize validation to function bodies/init.
>   expressions.
> - Introduce a new Interface for the WasmFullDecoder for init.
>   expressions.
> - Differentiate between constant and non-constant opcodes in
>   WasmFullDecoder.
> - Change representation of init. expressions in WasmModule to
>   WireBytesRef.
> - Reimplement EvaluateInitExpression in module-instantiate to re-decode
>   initializer expressions.
> - Remove some now-invalid module decoder tests.
>
> Pending changes:
> - Also refactor initializer expressions for element segment entries.
> - Reintroduce deleted tests.
>
> Bug: v8:11895
> Change-Id: I76512bfe1386c8338667d30fa6db93880a1e4b42
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2972910
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#75476}

Bug: v8:11895
Change-Id: I9fcfdedad73ef21beb9632f50305b8e678a2dff6
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2997582
Auto-Submit: Clemens Backes <clemensb@chromium.org>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/heads/master@{#75484}
parent 1485bfb7
......@@ -1937,8 +1937,6 @@ filegroup(
"src/wasm/function-compiler.h",
"src/wasm/graph-builder-interface.cc",
"src/wasm/graph-builder-interface.h",
"src/wasm/init-expr-interface.cc",
"src/wasm/init-expr-interface.h",
"src/wasm/jump-table-assembler.cc",
"src/wasm/jump-table-assembler.h",
"src/wasm/leb-helper.h",
......
......@@ -3167,7 +3167,6 @@ v8_header_set("v8_internal_headers") {
"src/wasm/function-body-decoder.h",
"src/wasm/function-compiler.h",
"src/wasm/graph-builder-interface.h",
"src/wasm/init-expr-interface.h",
"src/wasm/jump-table-assembler.h",
"src/wasm/leb-helper.h",
"src/wasm/local-decl-encoder.h",
......@@ -4104,7 +4103,6 @@ v8_source_set("v8_base_without_compiler") {
"src/wasm/function-body-decoder.cc",
"src/wasm/function-compiler.cc",
"src/wasm/graph-builder-interface.cc",
"src/wasm/init-expr-interface.cc",
"src/wasm/jump-table-assembler.cc",
"src/wasm/local-decl-encoder.cc",
"src/wasm/memory-protection-key.cc",
......
This diff is collapsed.
// 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/init-expr-interface.h"
#include "src/execution/isolate.h"
#include "src/handles/handles-inl.h"
#include "src/objects/fixed-array-inl.h"
#include "src/objects/oddball.h"
#include "src/roots/roots-inl.h"
#include "src/wasm/decoder.h"
#include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/wasm-objects.h"
namespace v8 {
namespace internal {
namespace wasm {
void InitExprInterface::I32Const(FullDecoder* decoder, Value* result,
int32_t value) {
if (isolate_ != nullptr) result->runtime_value = WasmValue(value);
}
void InitExprInterface::I64Const(FullDecoder* decoder, Value* result,
int64_t value) {
if (isolate_ != nullptr) result->runtime_value = WasmValue(value);
}
void InitExprInterface::F32Const(FullDecoder* decoder, Value* result,
float value) {
if (isolate_ != nullptr) result->runtime_value = WasmValue(value);
}
void InitExprInterface::F64Const(FullDecoder* decoder, Value* result,
double value) {
if (isolate_ != nullptr) result->runtime_value = WasmValue(value);
}
void InitExprInterface::S128Const(FullDecoder* decoder,
Simd128Immediate<validate>& imm,
Value* result) {
if (isolate_ == nullptr) return;
result->runtime_value = WasmValue(imm.value, kWasmS128);
}
void InitExprInterface::RefNull(FullDecoder* decoder, ValueType type,
Value* result) {
if (isolate_ == nullptr) return;
result->runtime_value = WasmValue(isolate_->factory()->null_value(), type);
}
void InitExprInterface::RefFunc(FullDecoder* decoder, uint32_t function_index,
Value* result) {
if (isolate_ != nullptr) {
auto function = WasmInstanceObject::GetOrCreateWasmExternalFunction(
isolate_, instance_, function_index);
result->runtime_value = WasmValue(
function, ValueType::Ref(module_->functions[function_index].sig_index,
kNonNullable));
} else {
outer_module_->functions[function_index].declared = true;
}
}
void InitExprInterface::GlobalGet(FullDecoder* decoder, Value* result,
const GlobalIndexImmediate<validate>& imm) {
if (isolate_ == nullptr) return;
const WasmGlobal& global = module_->globals[imm.index];
result->runtime_value =
global.type.is_numeric()
? WasmValue(GetRawUntaggedGlobalPtr(global), global.type)
: WasmValue(handle(tagged_globals_->get(global.offset), isolate_),
global.type);
}
void InitExprInterface::StructNewWithRtt(
FullDecoder* decoder, const StructIndexImmediate<validate>& imm,
const Value& rtt, const Value args[], Value* result) {
if (isolate_ == nullptr) return;
std::vector<WasmValue> field_values(imm.struct_type->field_count());
for (size_t i = 0; i < field_values.size(); i++) {
field_values[i] = args[i].runtime_value;
}
result->runtime_value =
WasmValue(isolate_->factory()->NewWasmStruct(
imm.struct_type, field_values.data(),
Handle<Map>::cast(rtt.runtime_value.to_ref())),
ValueType::Ref(HeapType(imm.index), kNonNullable));
}
void InitExprInterface::ArrayInit(FullDecoder* decoder,
const ArrayIndexImmediate<validate>& imm,
const base::Vector<Value>& elements,
const Value& rtt, Value* result) {
if (isolate_ == nullptr) return;
std::vector<WasmValue> element_values;
for (Value elem : elements) element_values.push_back(elem.runtime_value);
result->runtime_value =
WasmValue(isolate_->factory()->NewWasmArray(
imm.array_type, element_values,
Handle<Map>::cast(rtt.runtime_value.to_ref())),
ValueType::Ref(HeapType(imm.index), kNonNullable));
}
void InitExprInterface::RttCanon(FullDecoder* decoder, uint32_t type_index,
Value* result) {
if (isolate_ == nullptr) return;
result->runtime_value = WasmValue(
handle(instance_->managed_object_maps().get(type_index), isolate_),
ValueType::Rtt(type_index, 0));
}
void InitExprInterface::RttSub(FullDecoder* decoder, uint32_t type_index,
const Value& parent, Value* result,
WasmRttSubMode mode) {
if (isolate_ == nullptr) return;
ValueType type = parent.type.has_depth()
? ValueType::Rtt(type_index, parent.type.depth() + 1)
: ValueType::Rtt(type_index);
result->runtime_value =
WasmValue(Handle<Object>::cast(AllocateSubRtt(
isolate_, instance_, type_index,
Handle<Map>::cast(parent.runtime_value.to_ref()), mode)),
type);
}
void InitExprInterface::DoReturn(FullDecoder* decoder,
uint32_t /*drop_values*/) {
end_found_ = true;
// End decoding on "end".
decoder->set_end(decoder->pc() + 1);
if (isolate_ != nullptr) result_ = decoder->stack_value(1)->runtime_value;
}
byte* InitExprInterface::GetRawUntaggedGlobalPtr(const WasmGlobal& global) {
return reinterpret_cast<byte*>(untagged_globals_->backing_store()) +
global.offset;
}
} // 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_INIT_EXPR_INTERFACE_H_
#define V8_WASM_INIT_EXPR_INTERFACE_H_
#include "src/wasm/decoder.h"
#include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/wasm-value.h"
namespace v8 {
namespace internal {
class WasmInstanceObject;
class JSArrayBuffer;
namespace wasm {
// An interface for WasmFullDecoder used to decode initializer expressions. This
// interface has two modes: only validation (when {isolate_ == nullptr}), which
// is used in module-decoder, and code-generation (when {isolate_ != nullptr}),
// which is used in module-instantiate. We merge two distinct functionalities
// in one class to reduce the number of WasmFullDecoder instantiations, and thus
// V8 binary code size.
class InitExprInterface {
public:
static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation;
static constexpr DecodingMode decoding_mode = kInitExpression;
struct Value : public ValueBase<validate> {
WasmValue runtime_value;
template <typename... Args>
explicit Value(Args&&... args) V8_NOEXCEPT
: ValueBase(std::forward<Args>(args)...) {}
};
using Control = ControlBase<Value, validate>;
using FullDecoder =
WasmFullDecoder<validate, InitExprInterface, decoding_mode>;
InitExprInterface(const WasmModule* module, Isolate* isolate,
Handle<WasmInstanceObject> instance,
Handle<FixedArray> tagged_globals,
Handle<JSArrayBuffer> untagged_globals)
: module_(module),
outer_module_(nullptr),
isolate_(isolate),
instance_(instance),
tagged_globals_(tagged_globals),
untagged_globals_(untagged_globals) {
DCHECK_NOT_NULL(isolate);
}
explicit InitExprInterface(WasmModule* outer_module)
: module_(nullptr), outer_module_(outer_module), isolate_(nullptr) {}
#define EMPTY_INTERFACE_FUNCTION(name, ...) \
V8_INLINE void name(FullDecoder* decoder, ##__VA_ARGS__) {}
INTERFACE_META_FUNCTIONS(EMPTY_INTERFACE_FUNCTION)
INTERFACE_NON_CONSTANT_FUNCTIONS(EMPTY_INTERFACE_FUNCTION)
#undef EMPTY_INTERFACE_FUNCTION
#define DECLARE_INTERFACE_FUNCTION(name, ...) \
void name(FullDecoder* decoder, ##__VA_ARGS__);
INTERFACE_CONSTANT_FUNCTIONS(DECLARE_INTERFACE_FUNCTION)
#undef DECLARE_INTERFACE_FUNCTION
WasmValue result() {
DCHECK_NOT_NULL(isolate_);
return result_;
}
bool end_found() { return end_found_; }
private:
byte* GetRawUntaggedGlobalPtr(const WasmGlobal& global);
bool end_found_ = false;
WasmValue result_;
const WasmModule* module_;
WasmModule* outer_module_;
Isolate* isolate_;
Handle<WasmInstanceObject> instance_;
Handle<FixedArray> tagged_globals_;
Handle<JSArrayBuffer> untagged_globals_;
};
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_INIT_EXPR_INTERFACE_H_
This diff is collapsed.
......@@ -171,7 +171,7 @@ V8_EXPORT_PRIVATE FunctionResult DecodeWasmFunctionForTesting(
const WasmModule* module, const byte* function_start,
const byte* function_end, Counters* counters);
V8_EXPORT_PRIVATE WireBytesRef
V8_EXPORT_PRIVATE WasmInitExpr
DecodeWasmInitExprForTesting(const WasmFeatures& enabled, const byte* start,
const byte* end, ValueType expected);
......
......@@ -15,7 +15,6 @@
#include "src/tracing/trace-event.h"
#include "src/utils/utils.h"
#include "src/wasm/code-space-access.h"
#include "src/wasm/init-expr-interface.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-engine.h"
......@@ -23,7 +22,6 @@
#include "src/wasm/wasm-import-wrapper-cache.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-opcodes-inl.h"
#include "src/wasm/wasm-subtyping.h"
#include "src/wasm/wasm-value.h"
......@@ -389,7 +387,7 @@ class InstanceBuilder {
// Process initialization of globals.
void InitGlobals(Handle<WasmInstanceObject> instance);
WasmValue EvaluateInitExpression(WireBytesRef init, ValueType expected,
WasmValue EvaluateInitExpression(const WasmInitExpr& init,
Handle<WasmInstanceObject> instance);
// Process the exports, creating wrappers for functions, tables, memories,
......@@ -867,8 +865,7 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
size_t dest_offset;
if (module_->is_memory64) {
uint64_t dest_offset_64 =
EvaluateInitExpression(segment.dest_addr, kWasmI64, instance)
.to_u64();
EvaluateInitExpression(segment.dest_addr, instance).to_u64();
// Clamp to {std::numeric_limits<size_t>::max()}, which is always an
// invalid offset.
DCHECK_GT(std::numeric_limits<size_t>::max(), instance->memory_size());
......@@ -876,8 +873,7 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
dest_offset_64, uint64_t{std::numeric_limits<size_t>::max()}));
} else {
dest_offset =
EvaluateInitExpression(segment.dest_addr, kWasmI32, instance)
.to_u32();
EvaluateInitExpression(segment.dest_addr, instance).to_u32();
}
if (!base::IsInBounds<size_t>(dest_offset, size, instance->memory_size())) {
......@@ -1536,25 +1532,78 @@ T* InstanceBuilder::GetRawUntaggedGlobalPtr(const WasmGlobal& global) {
}
WasmValue InstanceBuilder::EvaluateInitExpression(
WireBytesRef init, ValueType expected,
Handle<WasmInstanceObject> instance) {
AccountingAllocator allocator;
Zone zone(&allocator, "consume_init_expr");
base::Vector<const byte> module_bytes =
instance->module_object().native_module()->wire_bytes();
FunctionBody body(FunctionSig::Build(&zone, {expected}, {}), init.offset(),
module_bytes.begin() + init.offset(),
module_bytes.begin() + init.end_offset());
WasmFeatures detected;
// We use kFullValidation so we do not have to create another instance of
// WasmFullDecoder, which would cost us >50Kb binary code size.
WasmFullDecoder<Decoder::kFullValidation, InitExprInterface, kInitExpression>
decoder(&zone, module_, WasmFeatures::All(), &detected, body, module_,
isolate_, instance, tagged_globals_, untagged_globals_);
decoder.DecodeFunctionBody();
return decoder.interface().result();
const WasmInitExpr& init, Handle<WasmInstanceObject> instance) {
switch (init.kind()) {
case WasmInitExpr::kNone:
UNREACHABLE();
case WasmInitExpr::kI32Const:
return WasmValue(init.immediate().i32_const);
case WasmInitExpr::kI64Const:
return WasmValue(init.immediate().i64_const);
case WasmInitExpr::kF32Const:
return WasmValue(init.immediate().f32_const);
case WasmInitExpr::kF64Const:
return WasmValue(init.immediate().f64_const);
case WasmInitExpr::kS128Const:
return WasmValue(Simd128(init.immediate().s128_const.data()));
case WasmInitExpr::kRefNullConst:
return WasmValue(handle(ReadOnlyRoots(isolate_).null_value(), isolate_),
init.type(module_, enabled_));
case WasmInitExpr::kRefFuncConst: {
auto function = WasmInstanceObject::GetOrCreateWasmExternalFunction(
isolate_, instance, init.immediate().index);
return WasmValue(function, init.type(module_, enabled_));
}
case WasmInitExpr::kGlobalGet: {
const WasmGlobal& global = module_->globals[init.immediate().index];
if (global.type.is_numeric()) {
return WasmValue(GetRawUntaggedGlobalPtr<byte>(global), global.type);
} else {
return WasmValue(handle(tagged_globals_->get(global.offset), isolate_),
init.type(module_, enabled_));
}
}
case WasmInitExpr::kStructNewWithRtt: {
const StructType* type = module_->struct_type(init.immediate().index);
std::vector<WasmValue> fields(type->field_count());
for (uint32_t i = 0; i < type->field_count(); i++) {
fields[i] = EvaluateInitExpression(init.operands()[i], instance);
}
auto rtt = Handle<Map>::cast(
EvaluateInitExpression(init.operands().back(), instance).to_ref());
return WasmValue(
isolate_->factory()->NewWasmStruct(type, fields.data(), rtt),
init.type(module_, enabled_));
}
case WasmInitExpr::kArrayInit: {
const ArrayType* type = module_->array_type(init.immediate().index);
std::vector<WasmValue> elements(init.operands().size() - 1);
for (uint32_t i = 0; i < elements.size(); i++) {
elements[i] = EvaluateInitExpression(init.operands()[i], instance);
}
auto rtt = Handle<Map>::cast(
EvaluateInitExpression(init.operands().back(), instance).to_ref());
return WasmValue(isolate_->factory()->NewWasmArray(type, elements, rtt),
init.type(module_, enabled_));
}
case WasmInitExpr::kRttCanon: {
int map_index = init.immediate().index;
return WasmValue(
handle(instance->managed_object_maps().get(map_index), isolate_),
init.type(module_, enabled_));
}
case WasmInitExpr::kRttSub:
case WasmInitExpr::kRttFreshSub: {
uint32_t type = init.immediate().index;
WasmValue parent = EvaluateInitExpression(init.operands()[0], instance);
return WasmValue(AllocateSubRtt(isolate_, instance, type,
Handle<Map>::cast(parent.to_ref()),
init.kind() == WasmInitExpr::kRttSub
? WasmRttSubMode::kCanonicalize
: WasmRttSubMode::kFresh),
init.type(module_, enabled_));
}
}
}
// Process initialization of globals.
......@@ -1562,10 +1611,9 @@ void InstanceBuilder::InitGlobals(Handle<WasmInstanceObject> instance) {
for (const WasmGlobal& global : module_->globals) {
if (global.mutability && global.imported) continue;
// Happens with imported globals.
if (!global.init.is_set()) continue;
if (global.init.kind() == WasmInitExpr::kNone) continue;
WasmValue value =
EvaluateInitExpression(global.init, global.type, instance);
WasmValue value = EvaluateInitExpression(global.init, instance);
if (global.type.is_reference()) {
tagged_globals_->set(global.offset, *value.to_ref());
......@@ -1784,16 +1832,16 @@ void InstanceBuilder::InitializeIndirectFunctionTables(
}
if (!table.type.is_defaultable()) {
WasmValue value =
EvaluateInitExpression(table.initial_value, table.type, instance);
DCHECK(WasmExportedFunction::IsWasmExportedFunction(*value.to_ref()));
auto wasm_external_function =
Handle<WasmExportedFunction>::cast(value.to_ref());
uint32_t func_index = wasm_external_function->function_index();
// Function constant is currently the only viable initializer.
DCHECK(table.initial_value.kind() == WasmInitExpr::kRefFuncConst);
uint32_t func_index = table.initial_value.immediate().index;
uint32_t sig_id =
module_->canonicalized_type_ids[module_->functions[func_index]
.sig_index];
MaybeHandle<WasmExternalFunction> wasm_external_function =
WasmInstanceObject::GetWasmExternalFunction(isolate_, instance,
func_index);
auto table_object = handle(
WasmTableObject::cast(instance->tables().get(table_index)), isolate_);
for (uint32_t entry_index = 0; entry_index < table.initial_size;
......@@ -1809,7 +1857,8 @@ void InstanceBuilder::InitializeIndirectFunctionTables(
WasmTableObject::SetFunctionTablePlaceholder(
isolate_, table_object, entry_index, instance, func_index);
} else {
table_object->entries().set(entry_index, *wasm_external_function);
table_object->entries().set(
entry_index, *wasm_external_function.ToHandleChecked());
}
// UpdateDispatchTables() updates all other dispatch tables, since
// we have not yet added the dispatch table we are currently building.
......@@ -1915,8 +1964,7 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
uint32_t table_index = elem_segment.table_index;
uint32_t dst =
EvaluateInitExpression(elem_segment.offset, kWasmI32, instance)
.to_u32();
EvaluateInitExpression(elem_segment.offset, instance).to_u32();
uint32_t src = 0;
size_t count = elem_segment.entries.size();
......
......@@ -71,7 +71,7 @@ struct WasmFunction {
struct WasmGlobal {
ValueType type; // type of the global.
bool mutability; // {true} if mutable.
WireBytesRef init; // the initialization expression of the global.
WasmInitExpr init; // the initialization expression of the global.
union {
uint32_t index; // index of imported mutable global.
uint32_t offset; // offset into global memory (if not imported & mutable).
......@@ -95,13 +95,13 @@ struct WasmException {
// Static representation of a wasm data segment.
struct WasmDataSegment {
// Construct an active segment.
explicit WasmDataSegment(WireBytesRef dest_addr)
explicit WasmDataSegment(WasmInitExpr dest_addr)
: dest_addr(std::move(dest_addr)), active(true) {}
// Construct a passive segment, which has no dest_addr.
WasmDataSegment() : active(false) {}
WireBytesRef dest_addr; // destination memory address of the data.
WasmInitExpr dest_addr; // destination memory address of the data.
WireBytesRef source; // start offset in the module bytes.
bool active = true; // true if copied automatically during instantiation.
};
......@@ -109,7 +109,7 @@ struct WasmDataSegment {
// Static representation of wasm element segment (table initializer).
struct WasmElemSegment {
// Construct an active segment.
WasmElemSegment(ValueType type, uint32_t table_index, WireBytesRef offset)
WasmElemSegment(ValueType type, uint32_t table_index, WasmInitExpr offset)
: type(type),
table_index(table_index),
offset(std::move(offset)),
......@@ -134,7 +134,7 @@ struct WasmElemSegment {
ValueType type;
uint32_t table_index;
WireBytesRef offset;
WasmInitExpr offset;
std::vector<WasmInitExpr> entries;
enum Status {
kStatusActive, // copied automatically during instantiation.
......@@ -377,7 +377,7 @@ struct WasmTable {
bool has_maximum_size = false; // true if there is a maximum size.
bool imported = false; // true if imported.
bool exported = false; // true if exported.
WireBytesRef initial_value;
WasmInitExpr initial_value;
};
inline bool is_asmjs_module(const WasmModule* module) {
......
......@@ -325,7 +325,7 @@ const WasmGlobal* TestingModuleBuilder::AddGlobal(ValueType type) {
byte size = type.element_size_bytes();
global_offset = (global_offset + size - 1) & ~(size - 1); // align
test_module_->globals.push_back(
{type, true, {}, {global_offset}, false, false});
{type, true, WasmInitExpr(), {global_offset}, false, false});
global_offset += size;
// limit number of globals.
CHECK_LT(global_offset, kMaxGlobalsSize);
......
......@@ -194,48 +194,6 @@ std::ostream& operator<<(std::ostream& os, const WasmInitExpr& expr) {
}
return os << ")";
}
// Appends an initializer expression encoded in {wire_bytes}, in the offset
// contained in {expr}.
// TODO(7748): Find a way to implement other expressions here.
void AppendInitExpr(std::ostream& os, ModuleWireBytes wire_bytes,
WireBytesRef expr) {
Decoder decoder(wire_bytes.module_bytes());
const byte* pc = wire_bytes.module_bytes().begin() + expr.offset();
uint32_t length;
os << "WasmInitExpr.";
switch (static_cast<WasmOpcode>(pc[0])) {
case kExprGlobalGet:
os << "GlobalGet("
<< decoder.read_u32v<Decoder::kNoValidation>(pc + 1, &length);
break;
case kExprI32Const:
os << "I32Const("
<< decoder.read_i32v<Decoder::kNoValidation>(pc + 1, &length);
break;
case kExprI64Const:
os << "I64Const("
<< decoder.read_i64v<Decoder::kNoValidation>(pc + 1, &length);
break;
case kExprF32Const: {
uint32_t result = decoder.read_u32<Decoder::kNoValidation>(pc + 1);
os << "F32Const(" << bit_cast<float>(result);
break;
}
case kExprF64Const: {
uint64_t result = decoder.read_u64<Decoder::kNoValidation>(pc + 1);
os << "F64Const(" << bit_cast<double>(result);
break;
}
case kExprRefFunc:
os << "RefFunc("
<< decoder.read_u32v<Decoder::kNoValidation>(pc + 1, &length);
break;
default:
UNREACHABLE();
}
os << ")";
}
} // namespace
void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
......@@ -291,9 +249,7 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
for (WasmGlobal& glob : module->globals) {
os << "builder.addGlobal(" << ValueTypeToConstantName(glob.type) << ", "
<< glob.mutability << ", ";
AppendInitExpr(os, wire_bytes, glob.init);
os << ");\n";
<< glob.mutability << ", " << glob.init << ");\n";
}
// TODO(7748): Support array/struct types.
......@@ -331,9 +287,7 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
: "Declarative";
os << "builder.add" << status_str << "ElementSegment(";
if (elem_segment.status == WasmElemSegment::kStatusActive) {
os << elem_segment.table_index << ", ";
AppendInitExpr(os, wire_bytes, elem_segment.offset);
os << ", ";
os << elem_segment.table_index << ", " << elem_segment.offset << ", ";
}
os << "[";
for (uint32_t i = 0; i < elem_segment.entries.size(); i++) {
......
......@@ -82,7 +82,8 @@ class TestModuleBuilder {
mod.origin = origin;
}
byte AddGlobal(ValueType type, bool mutability = true) {
mod.globals.push_back({type, mutability, {}, {0}, false, false});
mod.globals.push_back(
{type, mutability, WasmInitExpr(), {0}, false, false});
CHECK_LE(mod.globals.size(), kMaxByteSizedLeb128);
return static_cast<byte>(mod.globals.size() - 1);
}
......
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