4c5b3609fd
As discussed in person, this adds the code from v8-native-prototype into
V8 proper, guarded by GYP flags that do not build the code by default.
Passing wasm=on to 'make' or setting v8_wasm as a GYP flag activates
building of this code.
An additional header file is added to and exported from the compiler
directory, src/compiler/wasm-compiler.h. This exposes a limited interface
with opaque Node and Graph types to the decoder to build TF graphs, as
well as functions to compile WASM graphs.
The mjsunit tests added are blacklisted because they fail without the
WASM object exposed to JS, which is also disabled by the build config
option.
This corresponds closely to 5981e06ebc
, with some formatting fixes and moving some files into src/compiler.
R=mstarzinger@chromium.org, bradnelson@chromium.org
BUG=
Review URL: https://codereview.chromium.org/1504713014
Cr-Commit-Position: refs/heads/master@{#32794}
848 lines
25 KiB
C++
848 lines
25 KiB
C++
// Copyright 2015 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 "test/unittests/test-utils.h"
|
|
|
|
#include "src/wasm/module-decoder.h"
|
|
#include "src/wasm/wasm-opcodes.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace wasm {
|
|
|
|
class WasmModuleVerifyTest : public TestWithZone {
|
|
public:
|
|
ModuleResult DecodeModule(const byte* module_start, const byte* module_end) {
|
|
return DecodeWasmModule(nullptr, zone(), module_start, module_end, false,
|
|
false);
|
|
}
|
|
};
|
|
|
|
|
|
#define EXPECT_VERIFIES(data) \
|
|
do { \
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data)); \
|
|
EXPECT_TRUE(result.ok()); \
|
|
} while (false)
|
|
|
|
|
|
#define EXPECT_FAILURE(data) \
|
|
do { \
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data)); \
|
|
EXPECT_FALSE(result.ok()); \
|
|
} while (false)
|
|
|
|
|
|
struct LocalTypePair {
|
|
uint8_t code;
|
|
LocalType type;
|
|
} kLocalTypes[] = {{kLocalI32, kAstI32},
|
|
{kLocalI64, kAstI64},
|
|
{kLocalF32, kAstF32},
|
|
{kLocalF64, kAstF64}};
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, DecodeEmpty) {
|
|
static const byte data[1]{kDeclEnd};
|
|
{
|
|
ModuleResult result = DecodeModule(data, data);
|
|
EXPECT_TRUE(result.ok());
|
|
}
|
|
{
|
|
ModuleResult result = DecodeModule(data, data + 1);
|
|
EXPECT_TRUE(result.ok());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneGlobal) {
|
|
const byte data[] = {
|
|
kDeclGlobals,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // name offset
|
|
kMemI32, // memory type
|
|
0, // exported
|
|
};
|
|
|
|
{
|
|
// Should decode to exactly one global.
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(1, result.val->globals->size());
|
|
EXPECT_EQ(0, result.val->functions->size());
|
|
EXPECT_EQ(0, result.val->data_segments->size());
|
|
|
|
WasmGlobal* global = &result.val->globals->back();
|
|
|
|
EXPECT_EQ(0, global->name_offset);
|
|
EXPECT_EQ(MachineType::Int32(), global->type);
|
|
EXPECT_EQ(0, global->offset);
|
|
EXPECT_EQ(false, global->exported);
|
|
}
|
|
|
|
for (size_t size = 1; size < arraysize(data); size++) {
|
|
// Should fall off end of module bytes.
|
|
ModuleResult result = DecodeModule(data, data + size);
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, ZeroGlobals) {
|
|
const byte data[] = {
|
|
kDeclGlobals, 0, // declare 0 globals
|
|
};
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
}
|
|
|
|
|
|
static void AppendUint32v(std::vector<byte>& buffer, uint32_t val) {
|
|
while (true) {
|
|
uint32_t next = val >> 7;
|
|
uint32_t out = val & 0x7f;
|
|
if (next) {
|
|
buffer.push_back(static_cast<byte>(0x80 | out));
|
|
val = next;
|
|
} else {
|
|
buffer.push_back(static_cast<byte>(out));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, NGlobals) {
|
|
const byte data[] = {
|
|
0, 0, 0, 0, // name offset
|
|
kMemI32, // memory type
|
|
0, // exported
|
|
};
|
|
for (uint32_t i = 0; i < 1000000; i = i * 7 + 1) {
|
|
std::vector<byte> buffer;
|
|
buffer.push_back(kDeclGlobals);
|
|
AppendUint32v(buffer, i);
|
|
for (int j = 0; j < i; j++) {
|
|
buffer.insert(buffer.end(), data, data + arraysize(data));
|
|
}
|
|
|
|
ModuleResult result = DecodeModule(&buffer[0], &buffer[0] + buffer.size());
|
|
EXPECT_TRUE(result.ok());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, GlobalWithInvalidNameOffset) {
|
|
const byte data[] = {
|
|
kDeclGlobals,
|
|
1, // declare one global
|
|
0,
|
|
3,
|
|
0,
|
|
0, // name offset
|
|
kMemI32, // memory type
|
|
0, // exported
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, GlobalWithInvalidMemoryType) {
|
|
const byte data[] = {
|
|
kDeclGlobals,
|
|
1, // declare one global
|
|
0,
|
|
0,
|
|
0,
|
|
0, // name offset
|
|
33, // memory type
|
|
0, // exported
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, TwoGlobals) {
|
|
const byte data[] = {
|
|
kDeclGlobals,
|
|
2,
|
|
0,
|
|
0,
|
|
0,
|
|
0, // #0: name offset
|
|
kMemF32, // memory type
|
|
0, // exported
|
|
0,
|
|
0,
|
|
0,
|
|
0, // #1: name offset
|
|
kMemF64, // memory type
|
|
1, // exported
|
|
};
|
|
|
|
{
|
|
// Should decode to exactly two globals.
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(2, result.val->globals->size());
|
|
EXPECT_EQ(0, result.val->functions->size());
|
|
EXPECT_EQ(0, result.val->data_segments->size());
|
|
|
|
WasmGlobal* g0 = &result.val->globals->at(0);
|
|
WasmGlobal* g1 = &result.val->globals->at(1);
|
|
|
|
EXPECT_EQ(0, g0->name_offset);
|
|
EXPECT_EQ(MachineType::Float32(), g0->type);
|
|
EXPECT_EQ(0, g0->offset);
|
|
EXPECT_EQ(false, g0->exported);
|
|
|
|
EXPECT_EQ(0, g1->name_offset);
|
|
EXPECT_EQ(MachineType::Float64(), g1->type);
|
|
EXPECT_EQ(0, g1->offset);
|
|
EXPECT_EQ(true, g1->exported);
|
|
}
|
|
|
|
for (size_t size = 1; size < arraysize(data); size++) {
|
|
// Should fall off end of module bytes.
|
|
ModuleResult result = DecodeModule(data, data + size);
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneSignature) {
|
|
static const byte data[] = {
|
|
kDeclSignatures, 1, 0, kLocalVoid // void -> void
|
|
};
|
|
EXPECT_VERIFIES(data);
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, MultipleSignatures) {
|
|
static const byte data[] = {
|
|
kDeclSignatures,
|
|
3,
|
|
0,
|
|
kLocalVoid, // void -> void
|
|
1,
|
|
kLocalI32,
|
|
kLocalF32, // f32 -> i32
|
|
2,
|
|
kLocalI32,
|
|
kLocalF64,
|
|
kLocalF64, // (f64,f64) -> i32
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(3, result.val->signatures->size());
|
|
if (result.val->signatures->size() == 3) {
|
|
EXPECT_EQ(0, result.val->signatures->at(0)->return_count());
|
|
EXPECT_EQ(1, result.val->signatures->at(1)->return_count());
|
|
EXPECT_EQ(1, result.val->signatures->at(2)->return_count());
|
|
|
|
EXPECT_EQ(0, result.val->signatures->at(0)->parameter_count());
|
|
EXPECT_EQ(1, result.val->signatures->at(1)->parameter_count());
|
|
EXPECT_EQ(2, result.val->signatures->at(2)->parameter_count());
|
|
}
|
|
|
|
for (size_t size = 1; size < arraysize(data); size++) {
|
|
ModuleResult result = DecodeModule(data, data + size);
|
|
// Should fall off the end of module bytes.
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, FunctionWithoutSig) {
|
|
static const byte data[] = {
|
|
kDeclFunctions, 1,
|
|
// func#0 ------------------------------------------------------
|
|
0, 0, // signature index
|
|
0, 0, 0, 0, // name offset
|
|
0, 0, 0, 0, // code start offset
|
|
0, 0, 0, 0, // code end offset
|
|
1, 2, // local int32 count
|
|
3, 4, // local int64 count
|
|
5, 6, // local float32 count
|
|
7, 8, // local float64 count
|
|
0, // exported
|
|
1 // external
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) {
|
|
const int kCodeStartOffset = 23;
|
|
const int kCodeEndOffset = kCodeStartOffset + 1;
|
|
|
|
static const byte data[] = {
|
|
kDeclSignatures, 1,
|
|
// sig#0 -------------------------------------------------------
|
|
0, 0, // void -> void
|
|
// func#0 ------------------------------------------------------
|
|
kDeclFunctions, 1,
|
|
kDeclFunctionLocals | kDeclFunctionExport | kDeclFunctionName, 0,
|
|
0, // signature index
|
|
9, 0, 0, 0, // name offset
|
|
11, 2, // local int32 count
|
|
13, 4, // local int64 count
|
|
15, 6, // local float32 count
|
|
17, 8, // local float64 count
|
|
1, 0, // size
|
|
kExprNop,
|
|
};
|
|
|
|
{
|
|
// Should decode to exactly one function.
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(0, result.val->globals->size());
|
|
EXPECT_EQ(1, result.val->signatures->size());
|
|
EXPECT_EQ(1, result.val->functions->size());
|
|
EXPECT_EQ(0, result.val->data_segments->size());
|
|
EXPECT_EQ(0, result.val->function_table->size());
|
|
|
|
WasmFunction* function = &result.val->functions->back();
|
|
|
|
EXPECT_EQ(9, function->name_offset);
|
|
EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
|
|
EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
|
|
|
|
EXPECT_EQ(523, function->local_int32_count);
|
|
EXPECT_EQ(1037, function->local_int64_count);
|
|
EXPECT_EQ(1551, function->local_float32_count);
|
|
EXPECT_EQ(2065, function->local_float64_count);
|
|
|
|
EXPECT_EQ(true, function->exported);
|
|
EXPECT_EQ(false, function->external);
|
|
}
|
|
|
|
for (size_t size = 5; size < arraysize(data); size++) {
|
|
// Should fall off end of module bytes.
|
|
ModuleResult result = DecodeModule(data, data + size);
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneFunctionImported) {
|
|
static const byte data[] = {
|
|
kDeclSignatures, 1,
|
|
// sig#0 -------------------------------------------------------
|
|
0, 0, // void -> void
|
|
kDeclFunctions, 1,
|
|
// func#0 ------------------------------------------------------
|
|
kDeclFunctionImport, // no name, no locals, imported
|
|
0, 0, // signature index
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(1, result.val->functions->size());
|
|
WasmFunction* function = &result.val->functions->back();
|
|
|
|
EXPECT_EQ(0, function->name_offset);
|
|
EXPECT_EQ(0, function->code_start_offset);
|
|
EXPECT_EQ(0, function->code_end_offset);
|
|
|
|
EXPECT_EQ(0, function->local_int32_count);
|
|
EXPECT_EQ(0, function->local_int64_count);
|
|
EXPECT_EQ(0, function->local_float32_count);
|
|
EXPECT_EQ(0, function->local_float64_count);
|
|
|
|
EXPECT_EQ(false, function->exported);
|
|
EXPECT_EQ(true, function->external);
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody) {
|
|
static const byte kCodeStartOffset = 11;
|
|
static const byte kCodeEndOffset = kCodeStartOffset + 1;
|
|
|
|
static const byte data[] = {
|
|
kDeclSignatures, 1,
|
|
// sig#0 -------------------------------------------------------
|
|
0, 0, // void -> void
|
|
kDeclFunctions, 1,
|
|
// func#0 ------------------------------------------------------
|
|
0, // no name, no locals
|
|
0, 0, // signature index
|
|
1, 0, // body size
|
|
kExprNop // body
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(1, result.val->functions->size());
|
|
WasmFunction* function = &result.val->functions->back();
|
|
|
|
EXPECT_EQ(0, function->name_offset);
|
|
EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
|
|
EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
|
|
|
|
EXPECT_EQ(0, function->local_int32_count);
|
|
EXPECT_EQ(0, function->local_int64_count);
|
|
EXPECT_EQ(0, function->local_float32_count);
|
|
EXPECT_EQ(0, function->local_float64_count);
|
|
|
|
EXPECT_EQ(false, function->exported);
|
|
EXPECT_EQ(false, function->external);
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) {
|
|
static const byte kCodeStartOffset = 19;
|
|
static const byte kCodeEndOffset = kCodeStartOffset + 1;
|
|
|
|
static const byte data[] = {
|
|
kDeclSignatures, 1,
|
|
// sig#0 -------------------------------------------------------
|
|
0, 0, // void -> void
|
|
kDeclFunctions, 1,
|
|
// func#0 ------------------------------------------------------
|
|
kDeclFunctionLocals, 0, 0, // signature index
|
|
1, 2, // local int32 count
|
|
3, 4, // local int64 count
|
|
5, 6, // local float32 count
|
|
7, 8, // local float64 count
|
|
1, 0, // body size
|
|
kExprNop // body
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(1, result.val->functions->size());
|
|
WasmFunction* function = &result.val->functions->back();
|
|
|
|
EXPECT_EQ(0, function->name_offset);
|
|
EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
|
|
EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
|
|
|
|
EXPECT_EQ(513, function->local_int32_count);
|
|
EXPECT_EQ(1027, function->local_int64_count);
|
|
EXPECT_EQ(1541, function->local_float32_count);
|
|
EXPECT_EQ(2055, function->local_float64_count);
|
|
|
|
EXPECT_EQ(false, function->exported);
|
|
EXPECT_EQ(false, function->external);
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) {
|
|
static const byte kCodeStartOffset = 2 + kDeclGlobalSize + 4 + 2 + 17;
|
|
static const byte kCodeEndOffset = kCodeStartOffset + 3;
|
|
|
|
static const byte data[] = {
|
|
// global#0 --------------------------------------------------
|
|
kDeclGlobals, 1, 0, 0, 0, 0, // name offset
|
|
kMemU8, // memory type
|
|
0, // exported
|
|
// sig#0 -----------------------------------------------------
|
|
kDeclSignatures, 1, 0, 0, // void -> void
|
|
// func#0 ----------------------------------------------------
|
|
kDeclFunctions, 1, kDeclFunctionLocals | kDeclFunctionName, 0,
|
|
0, // signature index
|
|
9, 0, 0, 0, // name offset
|
|
1, 2, // local int32 count
|
|
3, 4, // local int64 count
|
|
5, 6, // local float32 count
|
|
7, 8, // local float64 count
|
|
3, 0, // body size
|
|
kExprNop, // func#0 body
|
|
kExprNop, // func#0 body
|
|
kExprNop, // func#0 body
|
|
// segment#0 -------------------------------------------------
|
|
kDeclDataSegments, 1, 0xae, 0xb3, 0x08, 0, // dest addr
|
|
15, 0, 0, 0, // source offset
|
|
5, 0, 0, 0, // source size
|
|
1, // init
|
|
// rest ------------------------------------------------------
|
|
kDeclEnd,
|
|
};
|
|
|
|
{
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(1, result.val->globals->size());
|
|
EXPECT_EQ(1, result.val->functions->size());
|
|
EXPECT_EQ(1, result.val->data_segments->size());
|
|
|
|
WasmGlobal* global = &result.val->globals->back();
|
|
|
|
EXPECT_EQ(0, global->name_offset);
|
|
EXPECT_EQ(MachineType::Uint8(), global->type);
|
|
EXPECT_EQ(0, global->offset);
|
|
EXPECT_EQ(false, global->exported);
|
|
|
|
WasmFunction* function = &result.val->functions->back();
|
|
|
|
EXPECT_EQ(9, function->name_offset);
|
|
EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
|
|
EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
|
|
|
|
EXPECT_EQ(false, function->exported);
|
|
EXPECT_EQ(false, function->external);
|
|
|
|
WasmDataSegment* segment = &result.val->data_segments->back();
|
|
|
|
EXPECT_EQ(0x8b3ae, segment->dest_addr);
|
|
EXPECT_EQ(15, segment->source_offset);
|
|
EXPECT_EQ(5, segment->source_size);
|
|
EXPECT_EQ(true, segment->init);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneDataSegment) {
|
|
const byte data[] = {
|
|
kDeclDataSegments,
|
|
1,
|
|
0xaa,
|
|
0xbb,
|
|
0x09,
|
|
0, // dest addr
|
|
11,
|
|
0,
|
|
0,
|
|
0, // source offset
|
|
3,
|
|
0,
|
|
0,
|
|
0, // source size
|
|
1, // init
|
|
};
|
|
|
|
{
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(0, result.val->globals->size());
|
|
EXPECT_EQ(0, result.val->functions->size());
|
|
EXPECT_EQ(1, result.val->data_segments->size());
|
|
|
|
WasmDataSegment* segment = &result.val->data_segments->back();
|
|
|
|
EXPECT_EQ(0x9bbaa, segment->dest_addr);
|
|
EXPECT_EQ(11, segment->source_offset);
|
|
EXPECT_EQ(3, segment->source_size);
|
|
EXPECT_EQ(true, segment->init);
|
|
}
|
|
|
|
for (size_t size = 1; size < arraysize(data); size++) {
|
|
// Should fall off end of module bytes.
|
|
ModuleResult result = DecodeModule(data, data + size);
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, TwoDataSegments) {
|
|
const byte data[] = {
|
|
kDeclDataSegments,
|
|
2,
|
|
0xee,
|
|
0xff,
|
|
0x07,
|
|
0, // dest addr
|
|
9,
|
|
0,
|
|
0,
|
|
0, // #0: source offset
|
|
4,
|
|
0,
|
|
0,
|
|
0, // source size
|
|
0, // init
|
|
0xcc,
|
|
0xdd,
|
|
0x06,
|
|
0, // #1: dest addr
|
|
6,
|
|
0,
|
|
0,
|
|
0, // source offset
|
|
10,
|
|
0,
|
|
0,
|
|
0, // source size
|
|
1, // init
|
|
};
|
|
|
|
{
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
EXPECT_EQ(0, result.val->globals->size());
|
|
EXPECT_EQ(0, result.val->functions->size());
|
|
EXPECT_EQ(2, result.val->data_segments->size());
|
|
|
|
WasmDataSegment* s0 = &result.val->data_segments->at(0);
|
|
WasmDataSegment* s1 = &result.val->data_segments->at(1);
|
|
|
|
EXPECT_EQ(0x7ffee, s0->dest_addr);
|
|
EXPECT_EQ(9, s0->source_offset);
|
|
EXPECT_EQ(4, s0->source_size);
|
|
EXPECT_EQ(false, s0->init);
|
|
|
|
EXPECT_EQ(0x6ddcc, s1->dest_addr);
|
|
EXPECT_EQ(6, s1->source_offset);
|
|
EXPECT_EQ(10, s1->source_size);
|
|
EXPECT_EQ(true, s1->init);
|
|
}
|
|
|
|
for (size_t size = 1; size < arraysize(data); size++) {
|
|
// Should fall off end of module bytes.
|
|
ModuleResult result = DecodeModule(data, data + size);
|
|
EXPECT_FALSE(result.ok());
|
|
}
|
|
}
|
|
|
|
|
|
// To make below tests for indirect calls much shorter.
|
|
#define FUNCTION(sig_index, external) \
|
|
kDeclFunctionImport, static_cast<byte>(sig_index), \
|
|
static_cast<byte>(sig_index >> 8)
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, OneIndirectFunction) {
|
|
static const byte data[] = {
|
|
// sig#0 -------------------------------------------------------
|
|
kDeclSignatures, 1, 0, 0, // void -> void
|
|
// func#0 ------------------------------------------------------
|
|
kDeclFunctions, 1, FUNCTION(0, 0),
|
|
// indirect table ----------------------------------------------
|
|
kDeclFunctionTable, 1, 0, 0};
|
|
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
if (result.ok()) {
|
|
EXPECT_EQ(1, result.val->signatures->size());
|
|
EXPECT_EQ(1, result.val->functions->size());
|
|
EXPECT_EQ(1, result.val->function_table->size());
|
|
EXPECT_EQ(0, result.val->function_table->at(0));
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
|
|
static const byte data[] = {
|
|
// sig#0 -------------------------------------------------------
|
|
kDeclSignatures, 2, 0, 0, // void -> void
|
|
0, kLocalI32, // void -> i32
|
|
// func#0 ------------------------------------------------------
|
|
kDeclFunctions, 4, FUNCTION(0, 1), FUNCTION(1, 1), FUNCTION(0, 1),
|
|
FUNCTION(1, 1),
|
|
// indirect table ----------------------------------------------
|
|
kDeclFunctionTable, 8, 0, 0, 1, 0, 2, 0, 3, 0, 0, 0, 1, 0, 2, 0, 3, 0,
|
|
};
|
|
|
|
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
if (result.ok()) {
|
|
EXPECT_EQ(2, result.val->signatures->size());
|
|
EXPECT_EQ(4, result.val->functions->size());
|
|
EXPECT_EQ(8, result.val->function_table->size());
|
|
for (int i = 0; i < 8; i++) {
|
|
EXPECT_EQ(i & 3, result.val->function_table->at(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, IndirectFunctionNoFunctions) {
|
|
static const byte data[] = {
|
|
// sig#0 -------------------------------------------------------
|
|
kDeclSignatures, 1, 0, 0, // void -> void
|
|
// indirect table ----------------------------------------------
|
|
kDeclFunctionTable, 1, 0, 0,
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
|
|
TEST_F(WasmModuleVerifyTest, IndirectFunctionInvalidIndex) {
|
|
static const byte data[] = {
|
|
// sig#0 -------------------------------------------------------
|
|
kDeclSignatures, 1, 0, 0, // void -> void
|
|
// functions ---------------------------------------------------
|
|
kDeclFunctions, 1, FUNCTION(0, 1),
|
|
// indirect table ----------------------------------------------
|
|
kDeclFunctionTable, 1, 1, 0,
|
|
};
|
|
|
|
EXPECT_FAILURE(data);
|
|
}
|
|
|
|
|
|
class WasmSignatureDecodeTest : public TestWithZone {};
|
|
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_v_v) {
|
|
static const byte data[] = {0, 0};
|
|
Zone zone;
|
|
FunctionSig* sig =
|
|
DecodeWasmSignatureForTesting(&zone, data, data + arraysize(data));
|
|
|
|
EXPECT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(0, sig->parameter_count());
|
|
EXPECT_EQ(0, sig->return_count());
|
|
}
|
|
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_t_v) {
|
|
for (size_t i = 0; i < arraysize(kLocalTypes); i++) {
|
|
LocalTypePair ret_type = kLocalTypes[i];
|
|
const byte data[] = {0, ret_type.code};
|
|
FunctionSig* sig =
|
|
DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
|
|
|
|
EXPECT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(0, sig->parameter_count());
|
|
EXPECT_EQ(1, sig->return_count());
|
|
EXPECT_EQ(ret_type.type, sig->GetReturn());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_v_t) {
|
|
for (size_t i = 0; i < arraysize(kLocalTypes); i++) {
|
|
LocalTypePair param_type = kLocalTypes[i];
|
|
const byte data[] = {1, 0, param_type.code};
|
|
FunctionSig* sig =
|
|
DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
|
|
|
|
EXPECT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(1, sig->parameter_count());
|
|
EXPECT_EQ(0, sig->return_count());
|
|
EXPECT_EQ(param_type.type, sig->GetParam(0));
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_t_t) {
|
|
for (size_t i = 0; i < arraysize(kLocalTypes); i++) {
|
|
LocalTypePair ret_type = kLocalTypes[i];
|
|
for (size_t j = 0; j < arraysize(kLocalTypes); j++) {
|
|
LocalTypePair param_type = kLocalTypes[j];
|
|
const byte data[] = {1, // param count
|
|
ret_type.code, // ret
|
|
param_type.code}; // param
|
|
FunctionSig* sig =
|
|
DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
|
|
|
|
EXPECT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(1, sig->parameter_count());
|
|
EXPECT_EQ(1, sig->return_count());
|
|
EXPECT_EQ(param_type.type, sig->GetParam(0));
|
|
EXPECT_EQ(ret_type.type, sig->GetReturn());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Ok_i_tt) {
|
|
for (size_t i = 0; i < arraysize(kLocalTypes); i++) {
|
|
LocalTypePair p0_type = kLocalTypes[i];
|
|
for (size_t j = 0; j < arraysize(kLocalTypes); j++) {
|
|
LocalTypePair p1_type = kLocalTypes[j];
|
|
const byte data[] = {2, // param count
|
|
kLocalI32, // ret
|
|
p0_type.code, // p0
|
|
p1_type.code}; // p1
|
|
FunctionSig* sig =
|
|
DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
|
|
|
|
EXPECT_TRUE(sig != nullptr);
|
|
EXPECT_EQ(2, sig->parameter_count());
|
|
EXPECT_EQ(1, sig->return_count());
|
|
EXPECT_EQ(p0_type.type, sig->GetParam(0));
|
|
EXPECT_EQ(p1_type.type, sig->GetParam(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Fail_off_end) {
|
|
byte data[256];
|
|
for (int p = 0; p <= 255; p = p + 1 + p * 3) {
|
|
for (int i = 0; i <= p; i++) data[i] = kLocalI32;
|
|
data[0] = static_cast<byte>(p);
|
|
|
|
for (int i = 0; i < p + 1; i++) {
|
|
// Should fall off the end for all signatures.
|
|
FunctionSig* sig = DecodeWasmSignatureForTesting(zone(), data, data + i);
|
|
EXPECT_EQ(nullptr, sig);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Fail_invalid_type) {
|
|
byte kInvalidType = 76;
|
|
for (int i = 1; i < 3; i++) {
|
|
byte data[] = {2, kLocalI32, kLocalI32, kLocalI32};
|
|
data[i] = kInvalidType;
|
|
FunctionSig* sig =
|
|
DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
|
|
EXPECT_EQ(nullptr, sig);
|
|
}
|
|
}
|
|
|
|
|
|
TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type) {
|
|
static const int kParamCount = 3;
|
|
for (int i = 0; i < kParamCount; i++) {
|
|
byte data[] = {kParamCount, kLocalI32, kLocalI32, kLocalI32, kLocalI32};
|
|
data[i + 2] = kLocalVoid;
|
|
FunctionSig* sig =
|
|
DecodeWasmSignatureForTesting(zone(), data, data + arraysize(data));
|
|
EXPECT_EQ(nullptr, sig);
|
|
}
|
|
}
|
|
|
|
|
|
class WasmFunctionVerifyTest : public TestWithZone {};
|
|
|
|
|
|
TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
|
|
byte data[] = {
|
|
0, kLocalVoid, // signature
|
|
3, 0, // local int32 count
|
|
4, 0, // local int64 count
|
|
5, 0, // local float32 count
|
|
6, 0, // local float64 count
|
|
kExprNop // body
|
|
};
|
|
|
|
FunctionResult result = DecodeWasmFunction(nullptr, zone(), nullptr, data,
|
|
data + arraysize(data));
|
|
EXPECT_TRUE(result.ok());
|
|
|
|
if (result.val && result.ok()) {
|
|
WasmFunction* function = result.val;
|
|
EXPECT_EQ(0, function->sig->parameter_count());
|
|
EXPECT_EQ(0, function->sig->return_count());
|
|
EXPECT_EQ(0, function->name_offset);
|
|
EXPECT_EQ(arraysize(data) - 1, function->code_start_offset);
|
|
EXPECT_EQ(arraysize(data), function->code_end_offset);
|
|
EXPECT_EQ(3, function->local_int32_count);
|
|
EXPECT_EQ(4, function->local_int64_count);
|
|
EXPECT_EQ(5, function->local_float32_count);
|
|
EXPECT_EQ(6, function->local_float64_count);
|
|
EXPECT_FALSE(function->external);
|
|
EXPECT_FALSE(function->exported);
|
|
}
|
|
}
|
|
} // namespace wasm
|
|
} // namespace internal
|
|
} // namespace v8
|