[wasm] Store local types in a plain array
After the let instruction was removed again, the number and types of locals stays constant throughout the decoding of a function. Hence store it in a plain array instead of a ZoneVector. This makes the decoder smaller and saves bounds checks for the "safe libc++". R=thibaudm@chromium.org Bug: chromium:1358853 Change-Id: Iad69aa0cfdc254710e1c2219cfb2c972241ef473 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3944929 Commit-Queue: Clemens Backes <clemensb@chromium.org> Reviewed-by: Thibaud Michaud <thibaudm@chromium.org> Cr-Commit-Position: refs/heads/main@{#83671}
This commit is contained in:
parent
a480c90950
commit
fb3321ea27
@ -1155,7 +1155,7 @@ class WasmDecoder : public Decoder {
|
||||
WasmFeatures* detected, const FunctionSig* sig, const byte* start,
|
||||
const byte* end, uint32_t buffer_offset = 0)
|
||||
: Decoder(start, end, buffer_offset),
|
||||
local_types_(zone),
|
||||
compilation_zone_(zone),
|
||||
module_(module),
|
||||
enabled_(enabled),
|
||||
detected_(detected),
|
||||
@ -1176,20 +1176,13 @@ class WasmDecoder : public Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
Zone* zone() const { return local_types_.get_allocator().zone(); }
|
||||
Zone* zone() const { return compilation_zone_; }
|
||||
|
||||
uint32_t num_locals() const {
|
||||
DCHECK_EQ(num_locals_, local_types_.size());
|
||||
return num_locals_;
|
||||
}
|
||||
uint32_t num_locals() const { return num_locals_; }
|
||||
|
||||
ValueType local_type(uint32_t index) const { return local_types_[index]; }
|
||||
|
||||
void InitializeLocalsFromSig() {
|
||||
DCHECK_NOT_NULL(sig_);
|
||||
DCHECK_EQ(0, this->local_types_.size());
|
||||
local_types_.assign(sig_->parameters().begin(), sig_->parameters().end());
|
||||
num_locals_ = static_cast<uint32_t>(sig_->parameters().size());
|
||||
ValueType local_type(uint32_t index) const {
|
||||
DCHECK_GE(num_locals_, index);
|
||||
return local_types_[index];
|
||||
}
|
||||
|
||||
// Decodes local definitions in the current decoder.
|
||||
@ -1197,6 +1190,12 @@ class WasmDecoder : public Decoder {
|
||||
// The decoded locals will be appended to {this->local_types_}.
|
||||
// The decoder's pc is not advanced.
|
||||
void DecodeLocals(const byte* pc, uint32_t* total_length) {
|
||||
DCHECK_NULL(local_types_);
|
||||
DCHECK_EQ(0, num_locals_);
|
||||
|
||||
// In a first step, count the number of locals and store the decoded
|
||||
// entries.
|
||||
num_locals_ = static_cast<uint32_t>(this->sig_->parameter_count());
|
||||
uint32_t length;
|
||||
*total_length = 0;
|
||||
|
||||
@ -1208,7 +1207,12 @@ class WasmDecoder : public Decoder {
|
||||
*total_length += length;
|
||||
TRACE("local decls count: %u\n", entries);
|
||||
|
||||
while (entries-- > 0) {
|
||||
struct DecodedLocalEntry {
|
||||
uint32_t count;
|
||||
ValueType type;
|
||||
};
|
||||
base::SmallVector<DecodedLocalEntry, 8> decoded_locals(entries);
|
||||
for (uint32_t entry = 0; entry < entries; ++entry) {
|
||||
if (!VALIDATE(more())) {
|
||||
return DecodeError(
|
||||
end(), "expected more local decls but reached end of input");
|
||||
@ -1219,8 +1223,8 @@ class WasmDecoder : public Decoder {
|
||||
if (!VALIDATE(ok())) {
|
||||
return DecodeError(pc + *total_length, "invalid local count");
|
||||
}
|
||||
DCHECK_LE(local_types_.size(), kV8MaxWasmFunctionLocals);
|
||||
if (!VALIDATE(count <= kV8MaxWasmFunctionLocals - local_types_.size())) {
|
||||
DCHECK_LE(num_locals_, kV8MaxWasmFunctionLocals);
|
||||
if (!VALIDATE(count <= kV8MaxWasmFunctionLocals - num_locals_)) {
|
||||
return DecodeError(pc + *total_length, "local count too large");
|
||||
}
|
||||
*total_length += length;
|
||||
@ -1230,10 +1234,28 @@ class WasmDecoder : public Decoder {
|
||||
if (!VALIDATE(ok())) return;
|
||||
*total_length += length;
|
||||
|
||||
local_types_.insert(local_types_.end(), count, type);
|
||||
num_locals_ += count;
|
||||
decoded_locals[entry] = DecodedLocalEntry{count, type};
|
||||
}
|
||||
DCHECK(ok());
|
||||
|
||||
if (num_locals_ == 0) return;
|
||||
|
||||
// Now build the array of local types from the parsed entries.
|
||||
local_types_ = compilation_zone_->NewArray<ValueType>(num_locals_);
|
||||
ValueType* locals_ptr = local_types_;
|
||||
|
||||
if (sig_->parameter_count() > 0) {
|
||||
std::copy(sig_->parameters().begin(), sig_->parameters().end(),
|
||||
locals_ptr);
|
||||
locals_ptr += sig_->parameter_count();
|
||||
}
|
||||
|
||||
for (auto& entry : decoded_locals) {
|
||||
std::fill_n(locals_ptr, entry.count, entry.type);
|
||||
locals_ptr += entry.count;
|
||||
}
|
||||
DCHECK_EQ(locals_ptr, local_types_ + num_locals_);
|
||||
}
|
||||
|
||||
// Shorthand that forwards to the {DecodeError} functions above, passing our
|
||||
@ -2359,13 +2381,9 @@ class WasmDecoder : public Decoder {
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// The {Zone} is implicitly stored in the {ZoneAllocator} which is part of
|
||||
// this {ZoneVector}. Hence save one field and just get it from there if
|
||||
// needed (see {zone()} accessor below).
|
||||
ZoneVector<ValueType> local_types_;
|
||||
Zone* const compilation_zone_;
|
||||
|
||||
// Cached value, for speed (yes, it's measurably faster to load this value
|
||||
// than to load the start and end pointer from a vector, subtract and shift).
|
||||
ValueType* local_types_ = nullptr;
|
||||
uint32_t num_locals_ = 0;
|
||||
|
||||
const WasmModule* module_;
|
||||
@ -2437,13 +2455,13 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
|
||||
DCHECK_EQ(this->num_locals(), 0);
|
||||
|
||||
locals_offset_ = this->pc_offset();
|
||||
this->InitializeLocalsFromSig();
|
||||
uint32_t params_count = this->num_locals();
|
||||
uint32_t locals_length;
|
||||
this->DecodeLocals(this->pc(), &locals_length);
|
||||
if (this->failed()) return TraceFailed();
|
||||
this->consume_bytes(locals_length);
|
||||
int non_defaultable = 0;
|
||||
uint32_t params_count =
|
||||
static_cast<uint32_t>(this->sig_->parameter_count());
|
||||
for (uint32_t index = params_count; index < this->num_locals(); index++) {
|
||||
if (!this->local_type(index).is_defaultable()) non_defaultable++;
|
||||
}
|
||||
|
@ -18,11 +18,11 @@ namespace wasm {
|
||||
|
||||
bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
|
||||
const WasmModule* module, const byte* start,
|
||||
const byte* end) {
|
||||
const byte* end, Zone* zone) {
|
||||
WasmFeatures no_features = WasmFeatures::None();
|
||||
Zone* zone = decls->type_list.get_allocator().zone();
|
||||
constexpr FixedSizeSignature<ValueType, 0, 0> kNoSig;
|
||||
WasmDecoder<Decoder::kFullValidation> decoder(
|
||||
zone, module, enabled, &no_features, nullptr, start, end, 0);
|
||||
zone, module, enabled, &no_features, &kNoSig, start, end, 0);
|
||||
uint32_t length;
|
||||
decoder.DecodeLocals(decoder.pc(), &length);
|
||||
if (decoder.failed()) {
|
||||
@ -31,20 +31,24 @@ bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
|
||||
}
|
||||
DCHECK(decoder.ok());
|
||||
decls->encoded_size = length;
|
||||
// Copy the decoded locals types into {decls->type_list}.
|
||||
DCHECK(decls->type_list.empty());
|
||||
decls->type_list = std::move(decoder.local_types_);
|
||||
// Copy the decoded locals types into {decls->local_types}.
|
||||
DCHECK_NULL(decls->local_types);
|
||||
decls->num_locals = decoder.num_locals_;
|
||||
decls->local_types = decoder.local_types_;
|
||||
return true;
|
||||
}
|
||||
|
||||
BytecodeIterator::BytecodeIterator(const byte* start, const byte* end)
|
||||
: Decoder(start, end) {}
|
||||
|
||||
BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
|
||||
BodyLocalDecls* decls)
|
||||
BodyLocalDecls* decls, Zone* zone)
|
||||
: Decoder(start, end) {
|
||||
if (decls != nullptr) {
|
||||
if (DecodeLocalDecls(WasmFeatures::All(), decls, nullptr, start, end)) {
|
||||
pc_ += decls->encoded_size;
|
||||
if (pc_ > end_) pc_ = end_;
|
||||
}
|
||||
DCHECK_NOT_NULL(decls);
|
||||
DCHECK_NOT_NULL(zone);
|
||||
if (DecodeLocalDecls(WasmFeatures::All(), decls, nullptr, start, end, zone)) {
|
||||
pc_ += decls->encoded_size;
|
||||
if (pc_ > end_) pc_ = end_;
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,19 +145,19 @@ bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
|
||||
}
|
||||
|
||||
// Print the local declarations.
|
||||
BodyLocalDecls decls(&zone);
|
||||
BytecodeIterator i(body.start, body.end, &decls);
|
||||
BodyLocalDecls decls;
|
||||
BytecodeIterator i(body.start, body.end, &decls, &zone);
|
||||
if (body.start != i.pc() && print_locals == kPrintLocals) {
|
||||
os << "// locals:";
|
||||
if (!decls.type_list.empty()) {
|
||||
ValueType type = decls.type_list[0];
|
||||
if (decls.num_locals > 0) {
|
||||
ValueType type = decls.local_types[0];
|
||||
uint32_t count = 0;
|
||||
for (size_t pos = 0; pos < decls.type_list.size(); ++pos) {
|
||||
if (decls.type_list[pos] == type) {
|
||||
for (size_t pos = 0; pos < decls.num_locals; ++pos) {
|
||||
if (decls.local_types[pos] == type) {
|
||||
++count;
|
||||
} else {
|
||||
os << " " << count << " " << type.name();
|
||||
type = decls.type_list[pos];
|
||||
type = decls.local_types[pos];
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
@ -64,15 +64,15 @@ struct BodyLocalDecls {
|
||||
// The size of the encoded declarations.
|
||||
uint32_t encoded_size = 0; // size of encoded declarations
|
||||
|
||||
ZoneVector<ValueType> type_list;
|
||||
|
||||
explicit BodyLocalDecls(Zone* zone) : type_list(zone) {}
|
||||
uint32_t num_locals = 0;
|
||||
ValueType* local_types = nullptr;
|
||||
};
|
||||
|
||||
V8_EXPORT_PRIVATE bool DecodeLocalDecls(const WasmFeatures& enabled,
|
||||
BodyLocalDecls* decls,
|
||||
const WasmModule* module,
|
||||
const byte* start, const byte* end);
|
||||
const byte* start, const byte* end,
|
||||
Zone* zone);
|
||||
|
||||
V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(
|
||||
Zone* zone, uint32_t num_locals, const byte* start, const byte* end);
|
||||
@ -150,11 +150,12 @@ class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) {
|
||||
: iterator_base(ptr, end), start_(start) {}
|
||||
};
|
||||
|
||||
// Create a new {BytecodeIterator}. If the {decls} pointer is non-null,
|
||||
// assume the bytecode starts with local declarations and decode them.
|
||||
// Otherwise, do not decode local decls.
|
||||
BytecodeIterator(const byte* start, const byte* end,
|
||||
BodyLocalDecls* decls = nullptr);
|
||||
// Create a new {BytecodeIterator}, starting after the locals declarations.
|
||||
BytecodeIterator(const byte* start, const byte* end);
|
||||
|
||||
// Create a new {BytecodeIterator}, starting with locals declarations.
|
||||
BytecodeIterator(const byte* start, const byte* end, BodyLocalDecls* decls,
|
||||
Zone* zone);
|
||||
|
||||
base::iterator_range<opcode_iterator> opcodes() {
|
||||
return base::iterator_range<opcode_iterator>(opcode_iterator(pc_, end_),
|
||||
|
@ -666,6 +666,7 @@ class ValueType {
|
||||
|
||||
uint32_t bit_field_;
|
||||
};
|
||||
ASSERT_TRIVIALLY_COPYABLE(ValueType);
|
||||
|
||||
inline constexpr intptr_t ValueType::kBitFieldOffset =
|
||||
offsetof(ValueType, bit_field_);
|
||||
|
@ -783,13 +783,13 @@ int FindNextBreakablePosition(wasm::NativeModule* native_module, int func_index,
|
||||
int offset_in_func) {
|
||||
AccountingAllocator alloc;
|
||||
Zone tmp(&alloc, ZONE_NAME);
|
||||
wasm::BodyLocalDecls locals(&tmp);
|
||||
wasm::BodyLocalDecls locals;
|
||||
const byte* module_start = native_module->wire_bytes().begin();
|
||||
const wasm::WasmFunction& func =
|
||||
native_module->module()->functions[func_index];
|
||||
wasm::BytecodeIterator iterator(module_start + func.code.offset(),
|
||||
module_start + func.code.end_offset(),
|
||||
&locals);
|
||||
&locals, &tmp);
|
||||
DCHECK_LT(0, locals.encoded_size);
|
||||
if (offset_in_func < 0) return 0;
|
||||
for (; iterator.has_next(); iterator.next()) {
|
||||
@ -1099,10 +1099,10 @@ bool WasmScript::GetPossibleBreakpoints(
|
||||
const wasm::WasmFunction& func = functions[func_idx];
|
||||
if (func.code.length() == 0) continue;
|
||||
|
||||
wasm::BodyLocalDecls locals(&tmp);
|
||||
wasm::BodyLocalDecls locals;
|
||||
wasm::BytecodeIterator iterator(module_start + func.code.offset(),
|
||||
module_start + func.code.end_offset(),
|
||||
&locals);
|
||||
&locals, &tmp);
|
||||
DCHECK_LT(0u, locals.encoded_size);
|
||||
for (; iterator.has_next(); iterator.next()) {
|
||||
uint32_t total_offset = func.code.offset() + iterator.pc_offset();
|
||||
|
@ -168,7 +168,6 @@ void FunctionBodyDisassembler::DecodeAsWat(MultiLineStringBuilder& out,
|
||||
|
||||
// Decode and print locals.
|
||||
uint32_t locals_length;
|
||||
InitializeLocalsFromSig();
|
||||
DecodeLocals(pc_, &locals_length);
|
||||
if (failed()) {
|
||||
// TODO(jkummerow): Improve error handling.
|
||||
|
@ -749,7 +749,7 @@ class SideTable : public ZoneObject {
|
||||
max_exception_arity, static_cast<int>(tag.sig->parameter_count()));
|
||||
}
|
||||
}
|
||||
for (BytecodeIterator i(code->start, code->end, &code->locals);
|
||||
for (BytecodeIterator i(code->start, code->end, &code->locals, zone);
|
||||
i.has_next(); i.next()) {
|
||||
WasmOpcode opcode = i.current();
|
||||
int32_t exceptional_stack_height = 0;
|
||||
@ -1119,8 +1119,8 @@ class CodeMap {
|
||||
|
||||
void AddFunction(const WasmFunction* function, const byte* code_start,
|
||||
const byte* code_end) {
|
||||
InterpreterCode code = {function, BodyLocalDecls(zone_), code_start,
|
||||
code_end, nullptr};
|
||||
InterpreterCode code = {function, BodyLocalDecls{}, code_start, code_end,
|
||||
nullptr};
|
||||
|
||||
DCHECK_EQ(interpreter_code_.size(), function->func_index);
|
||||
interpreter_code_.push_back(code);
|
||||
@ -1334,7 +1334,7 @@ class WasmInterpreterInternals {
|
||||
// Limit of parameters.
|
||||
sp_t plimit() { return sp + code->function->sig->parameter_count(); }
|
||||
// Limit of locals.
|
||||
sp_t llimit() { return plimit() + code->locals.type_list.size(); }
|
||||
sp_t llimit() { return plimit() + code->locals.num_locals; }
|
||||
|
||||
Handle<FixedArray> caught_exception_stack;
|
||||
};
|
||||
@ -1407,7 +1407,7 @@ class WasmInterpreterInternals {
|
||||
// Check if there is room for a function's activation.
|
||||
void EnsureStackSpaceForCall(InterpreterCode* code) {
|
||||
EnsureStackSpace(code->side_table->max_stack_height_ +
|
||||
code->locals.type_list.size());
|
||||
code->locals.num_locals);
|
||||
DCHECK_GE(StackHeight(), code->function->sig->parameter_count());
|
||||
}
|
||||
|
||||
@ -1430,7 +1430,8 @@ class WasmInterpreterInternals {
|
||||
}
|
||||
|
||||
pc_t InitLocals(InterpreterCode* code) {
|
||||
for (ValueType p : code->locals.type_list) {
|
||||
for (ValueType p :
|
||||
base::VectorOf(code->locals.local_types, code->locals.num_locals)) {
|
||||
WasmValue val;
|
||||
switch (p.kind()) {
|
||||
#define CASE_TYPE(valuetype, ctype) \
|
||||
@ -3313,8 +3314,7 @@ class WasmInterpreterInternals {
|
||||
DCHECK(!frames_.empty());
|
||||
// There must be enough space on the stack to hold the arguments, locals,
|
||||
// and the value stack.
|
||||
DCHECK_LE(code->function->sig->parameter_count() +
|
||||
code->locals.type_list.size() +
|
||||
DCHECK_LE(code->function->sig->parameter_count() + code->locals.num_locals +
|
||||
code->side_table->max_stack_height_,
|
||||
stack_limit_ - stack_.get() - frames_.back().sp);
|
||||
// Seal the surrounding {HandleScope} to ensure that all cases within the
|
||||
@ -4242,7 +4242,7 @@ ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
|
||||
false, // imported
|
||||
false, // exported
|
||||
false}; // declared
|
||||
InterpreterCode code{&function, BodyLocalDecls(zone), start, end, nullptr};
|
||||
InterpreterCode code{&function, BodyLocalDecls{}, start, end, nullptr};
|
||||
|
||||
// Now compute and return the control transfers.
|
||||
SideTable side_table(zone, module, &code);
|
||||
|
@ -681,15 +681,15 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
||||
<< " /* sig */)\n";
|
||||
|
||||
// Add locals.
|
||||
BodyLocalDecls decls(&tmp_zone);
|
||||
BodyLocalDecls decls;
|
||||
DecodeLocalDecls(enabled_features, &decls, module, func_code.begin(),
|
||||
func_code.end());
|
||||
if (!decls.type_list.empty()) {
|
||||
func_code.end(), &tmp_zone);
|
||||
if (decls.num_locals) {
|
||||
os << " ";
|
||||
for (size_t pos = 0, count = 1, locals = decls.type_list.size();
|
||||
pos < locals; pos += count, count = 1) {
|
||||
ValueType type = decls.type_list[pos];
|
||||
while (pos + count < locals && decls.type_list[pos + count] == type) {
|
||||
for (size_t pos = 0, count = 1, locals = decls.num_locals; pos < locals;
|
||||
pos += count, count = 1) {
|
||||
ValueType type = decls.local_types[pos];
|
||||
while (pos + count < locals && decls.local_types[pos + count] == type) {
|
||||
++count;
|
||||
}
|
||||
os << ".addLocals(" << ValueTypeToConstantName(type) << ", " << count
|
||||
|
@ -4991,17 +4991,15 @@ TEST_F(TypeReaderTest, HeapTypeDecodingTest) {
|
||||
}
|
||||
}
|
||||
|
||||
using TypesOfLocals = ZoneVector<ValueType>;
|
||||
|
||||
class LocalDeclDecoderTest : public TestWithZone {
|
||||
public:
|
||||
v8::internal::AccountingAllocator allocator;
|
||||
WasmFeatures enabled_features_;
|
||||
|
||||
size_t ExpectRun(TypesOfLocals map, size_t pos, ValueType expected,
|
||||
size_t ExpectRun(ValueType* local_types, size_t pos, ValueType expected,
|
||||
size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
EXPECT_EQ(expected, map[pos++]);
|
||||
EXPECT_EQ(expected, local_types[pos++]);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
@ -5010,27 +5008,27 @@ class LocalDeclDecoderTest : public TestWithZone {
|
||||
const byte* end) {
|
||||
WasmModule module;
|
||||
return i::wasm::DecodeLocalDecls(enabled_features_, decls, &module, start,
|
||||
end);
|
||||
end, zone());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(LocalDeclDecoderTest, EmptyLocals) {
|
||||
BodyLocalDecls decls(zone());
|
||||
BodyLocalDecls decls;
|
||||
bool result = DecodeLocalDecls(&decls, nullptr, nullptr);
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
|
||||
TEST_F(LocalDeclDecoderTest, NoLocals) {
|
||||
static const byte data[] = {0};
|
||||
BodyLocalDecls decls(zone());
|
||||
BodyLocalDecls decls;
|
||||
bool result = DecodeLocalDecls(&decls, data, data + sizeof(data));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(decls.type_list.empty());
|
||||
EXPECT_EQ(0u, decls.num_locals);
|
||||
}
|
||||
|
||||
TEST_F(LocalDeclDecoderTest, WrongLocalDeclsCount1) {
|
||||
static const byte data[] = {1};
|
||||
BodyLocalDecls decls(zone());
|
||||
BodyLocalDecls decls;
|
||||
bool result = DecodeLocalDecls(&decls, data, data + sizeof(data));
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
@ -5038,7 +5036,7 @@ TEST_F(LocalDeclDecoderTest, WrongLocalDeclsCount1) {
|
||||
TEST_F(LocalDeclDecoderTest, WrongLocalDeclsCount2) {
|
||||
static const byte data[] = {2, 1,
|
||||
static_cast<byte>(kWasmI32.value_type_code())};
|
||||
BodyLocalDecls decls(zone());
|
||||
BodyLocalDecls decls;
|
||||
bool result = DecodeLocalDecls(&decls, data, data + sizeof(data));
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
@ -5047,13 +5045,12 @@ TEST_F(LocalDeclDecoderTest, OneLocal) {
|
||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||
ValueType type = kValueTypes[i];
|
||||
const byte data[] = {1, 1, static_cast<byte>(type.value_type_code())};
|
||||
BodyLocalDecls decls(zone());
|
||||
BodyLocalDecls decls;
|
||||
bool result = DecodeLocalDecls(&decls, data, data + sizeof(data));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(1u, decls.type_list.size());
|
||||
EXPECT_EQ(1u, decls.num_locals);
|
||||
|
||||
TypesOfLocals map = decls.type_list;
|
||||
EXPECT_EQ(type, map[0]);
|
||||
EXPECT_EQ(type, decls.local_types[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5061,15 +5058,12 @@ TEST_F(LocalDeclDecoderTest, FiveLocals) {
|
||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||
ValueType type = kValueTypes[i];
|
||||
const byte data[] = {1, 5, static_cast<byte>(type.value_type_code())};
|
||||
BodyLocalDecls decls(zone());
|
||||
BodyLocalDecls decls;
|
||||
bool result = DecodeLocalDecls(&decls, data, data + sizeof(data));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sizeof(data), decls.encoded_size);
|
||||
EXPECT_EQ(5u, decls.type_list.size());
|
||||
|
||||
TypesOfLocals map = decls.type_list;
|
||||
EXPECT_EQ(5u, map.size());
|
||||
ExpectRun(map, 0, type, 5);
|
||||
EXPECT_EQ(5u, decls.num_locals);
|
||||
ExpectRun(decls.local_types, 0, type, 5);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5080,20 +5074,17 @@ TEST_F(LocalDeclDecoderTest, MixedLocals) {
|
||||
for (byte d = 0; d < 3; d++) {
|
||||
const byte data[] = {4, a, kI32Code, b, kI64Code,
|
||||
c, kF32Code, d, kF64Code};
|
||||
BodyLocalDecls decls(zone());
|
||||
BodyLocalDecls decls;
|
||||
bool result = DecodeLocalDecls(&decls, data, data + sizeof(data));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sizeof(data), decls.encoded_size);
|
||||
EXPECT_EQ(static_cast<uint32_t>(a + b + c + d),
|
||||
decls.type_list.size());
|
||||
|
||||
TypesOfLocals map = decls.type_list;
|
||||
EXPECT_EQ(static_cast<uint32_t>(a + b + c + d), decls.num_locals);
|
||||
|
||||
size_t pos = 0;
|
||||
pos = ExpectRun(map, pos, kWasmI32, a);
|
||||
pos = ExpectRun(map, pos, kWasmI64, b);
|
||||
pos = ExpectRun(map, pos, kWasmF32, c);
|
||||
pos = ExpectRun(map, pos, kWasmF64, d);
|
||||
pos = ExpectRun(decls.local_types, pos, kWasmI32, a);
|
||||
pos = ExpectRun(decls.local_types, pos, kWasmI64, b);
|
||||
pos = ExpectRun(decls.local_types, pos, kWasmF32, c);
|
||||
pos = ExpectRun(decls.local_types, pos, kWasmF64, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5110,16 +5101,15 @@ TEST_F(LocalDeclDecoderTest, UseEncoder) {
|
||||
local_decls.AddLocals(212, kWasmI64);
|
||||
local_decls.Prepend(zone(), &data, &end);
|
||||
|
||||
BodyLocalDecls decls(zone());
|
||||
BodyLocalDecls decls;
|
||||
bool result = DecodeLocalDecls(&decls, data, end);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(5u + 1337u + 212u, decls.type_list.size());
|
||||
EXPECT_EQ(5u + 1337u + 212u, decls.num_locals);
|
||||
|
||||
TypesOfLocals map = decls.type_list;
|
||||
size_t pos = 0;
|
||||
pos = ExpectRun(map, pos, kWasmF32, 5);
|
||||
pos = ExpectRun(map, pos, kWasmI32, 1337);
|
||||
pos = ExpectRun(map, pos, kWasmI64, 212);
|
||||
pos = ExpectRun(decls.local_types, pos, kWasmF32, 5);
|
||||
pos = ExpectRun(decls.local_types, pos, kWasmI32, 1337);
|
||||
pos = ExpectRun(decls.local_types, pos, kWasmI64, 212);
|
||||
}
|
||||
|
||||
TEST_F(LocalDeclDecoderTest, InvalidTypeIndex) {
|
||||
@ -5130,7 +5120,7 @@ TEST_F(LocalDeclDecoderTest, InvalidTypeIndex) {
|
||||
LocalDeclEncoder local_decls(zone());
|
||||
|
||||
local_decls.AddLocals(1, ValueType::RefNull(0));
|
||||
BodyLocalDecls decls(zone());
|
||||
BodyLocalDecls decls;
|
||||
bool result = DecodeLocalDecls(&decls, data, end);
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
@ -5195,8 +5185,8 @@ TEST_F(BytecodeIteratorTest, ForeachOffset) {
|
||||
|
||||
TEST_F(BytecodeIteratorTest, WithLocalDecls) {
|
||||
byte code[] = {1, 1, kI32Code, WASM_I32V_1(9), WASM_I32V_1(11)};
|
||||
BodyLocalDecls decls(zone());
|
||||
BytecodeIterator iter(code, code + sizeof(code), &decls);
|
||||
BodyLocalDecls decls;
|
||||
BytecodeIterator iter(code, code + sizeof(code), &decls, zone());
|
||||
|
||||
EXPECT_EQ(3u, decls.encoded_size);
|
||||
EXPECT_EQ(3u, iter.pc_offset());
|
||||
|
@ -234,7 +234,6 @@ class ExtendedFunctionDis : public FunctionBodyDisassembler {
|
||||
|
||||
// Decode and print locals.
|
||||
uint32_t locals_length;
|
||||
InitializeLocalsFromSig();
|
||||
DecodeLocals(pc_, &locals_length);
|
||||
if (failed()) {
|
||||
// TODO(jkummerow): Better error handling.
|
||||
|
Loading…
Reference in New Issue
Block a user