blob: 740c0540dc89a2ad65674b774abb91c402e8915d [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "test/unittests/test-utils.h"
6
7#include "src/v8.h"
8
9#include "src/wasm/ast-decoder.h"
10#include "src/wasm/encoder.h"
11
12namespace v8 {
13namespace internal {
14namespace wasm {
15
16class EncoderTest : public TestWithZone {
17 protected:
18 void AddLocal(WasmFunctionBuilder* f, LocalType type) {
19 uint16_t index = f->AddLocal(type);
20 const std::vector<uint8_t>& out_index = UnsignedLEB128From(index);
21 std::vector<uint8_t> code;
22 code.push_back(kExprGetLocal);
23 for (size_t i = 0; i < out_index.size(); i++) {
24 code.push_back(out_index.at(i));
25 }
26 uint32_t local_indices[] = {1};
27 f->EmitCode(&code[0], static_cast<uint32_t>(code.size()), local_indices, 1);
28 }
29
30 void CheckReadValue(uint8_t* leb_value, uint32_t expected_result,
31 int expected_length,
32 ReadUnsignedLEB128ErrorCode expected_error_code) {
33 int length;
34 uint32_t result;
35 ReadUnsignedLEB128ErrorCode error_code =
36 ReadUnsignedLEB128Operand(leb_value, leb_value + 5, &length, &result);
37 CHECK_EQ(error_code, expected_error_code);
38 if (error_code == 0) {
39 CHECK_EQ(result, expected_result);
40 CHECK_EQ(length, expected_length);
41 }
42 }
43
44 void CheckWriteValue(uint32_t input, int length, uint8_t* vals) {
45 const std::vector<uint8_t> result = UnsignedLEB128From(input);
46 CHECK_EQ(result.size(), length);
47 for (int i = 0; i < length; i++) {
48 CHECK_EQ(result.at(i), vals[i]);
49 }
50 }
51};
52
53
54TEST_F(EncoderTest, Function_Builder_Variable_Indexing) {
Ben Murdochda12d292016-06-02 14:46:10 +010055 base::AccountingAllocator allocator;
56 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057 WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
58 uint16_t f_index = builder->AddFunction();
59 WasmFunctionBuilder* function = builder->FunctionAt(f_index);
Ben Murdoch097c5b22016-05-18 11:27:45 +010060 uint16_t local_f32 = function->AddLocal(kAstF32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061 uint16_t param_float32 = function->AddParam(kAstF32);
Ben Murdoch097c5b22016-05-18 11:27:45 +010062 uint16_t local_i32 = function->AddLocal(kAstI32);
63 uint16_t local_f64 = function->AddLocal(kAstF64);
64 uint16_t local_i64 = function->AddLocal(kAstI64);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 uint16_t param_int32 = function->AddParam(kAstI32);
Ben Murdoch097c5b22016-05-18 11:27:45 +010066 uint16_t local_i32_2 = function->AddLocal(kAstI32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067
68 byte code[] = {kExprGetLocal, static_cast<uint8_t>(param_float32)};
69 uint32_t local_indices[] = {1};
70 function->EmitCode(code, sizeof(code), local_indices, 1);
71 code[1] = static_cast<uint8_t>(param_int32);
72 function->EmitCode(code, sizeof(code), local_indices, 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +010073 code[1] = static_cast<uint8_t>(local_i32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074 function->EmitCode(code, sizeof(code), local_indices, 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +010075 code[1] = static_cast<uint8_t>(local_i32_2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000076 function->EmitCode(code, sizeof(code), local_indices, 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +010077 code[1] = static_cast<uint8_t>(local_i64);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078 function->EmitCode(code, sizeof(code), local_indices, 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +010079 code[1] = static_cast<uint8_t>(local_f32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080 function->EmitCode(code, sizeof(code), local_indices, 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +010081 code[1] = static_cast<uint8_t>(local_f64);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082 function->EmitCode(code, sizeof(code), local_indices, 1);
83
84 WasmFunctionEncoder* f = function->Build(&zone, builder);
85 ZoneVector<uint8_t> buffer_vector(f->HeaderSize() + f->BodySize(), &zone);
86 byte* buffer = &buffer_vector[0];
87 byte* header = buffer;
88 byte* body = buffer + f->HeaderSize();
89 f->Serialize(buffer, &header, &body);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000090}
91
92
93TEST_F(EncoderTest, Function_Builder_Indexing_Variable_Width) {
Ben Murdochda12d292016-06-02 14:46:10 +010094 base::AccountingAllocator allocator;
95 Zone zone(&allocator);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
97 uint16_t f_index = builder->AddFunction();
98 WasmFunctionBuilder* function = builder->FunctionAt(f_index);
99 for (size_t i = 0; i < 128; i++) {
100 AddLocal(function, kAstF32);
101 }
102 AddLocal(function, kAstI32);
103
104 WasmFunctionEncoder* f = function->Build(&zone, builder);
105 ZoneVector<uint8_t> buffer_vector(f->HeaderSize() + f->BodySize(), &zone);
106 byte* buffer = &buffer_vector[0];
107 byte* header = buffer;
108 byte* body = buffer + f->HeaderSize();
109 f->Serialize(buffer, &header, &body);
110 body = buffer + f->HeaderSize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111}
112
Ben Murdochda12d292016-06-02 14:46:10 +0100113TEST_F(EncoderTest, Function_Builder_Block_Variable_Width) {
114 base::AccountingAllocator allocator;
115 Zone zone(&allocator);
116 WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
117 uint16_t f_index = builder->AddFunction();
118 WasmFunctionBuilder* function = builder->FunctionAt(f_index);
119 function->EmitWithVarInt(kExprBlock, 200);
120 for (int i = 0; i < 200; ++i) {
121 function->Emit(kExprNop);
122 }
123
124 WasmFunctionEncoder* f = function->Build(&zone, builder);
125 CHECK_EQ(f->BodySize(), 204);
126}
127
128TEST_F(EncoderTest, Function_Builder_EmitEditableVarIntImmediate) {
129 base::AccountingAllocator allocator;
130 Zone zone(&allocator);
131 WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
132 uint16_t f_index = builder->AddFunction();
133 WasmFunctionBuilder* function = builder->FunctionAt(f_index);
134 function->Emit(kExprLoop);
135 uint32_t offset = function->EmitEditableVarIntImmediate();
136 for (int i = 0; i < 200; ++i) {
137 function->Emit(kExprNop);
138 }
139 function->EditVarIntImmediate(offset, 200);
140
141 WasmFunctionEncoder* f = function->Build(&zone, builder);
142 CHECK_EQ(f->BodySize(), 204);
143}
144
145TEST_F(EncoderTest, Function_Builder_EmitEditableVarIntImmediate_Locals) {
146 base::AccountingAllocator allocator;
147 Zone zone(&allocator);
148 WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
149 uint16_t f_index = builder->AddFunction();
150 WasmFunctionBuilder* function = builder->FunctionAt(f_index);
151 function->Emit(kExprBlock);
152 uint32_t offset = function->EmitEditableVarIntImmediate();
153 for (int i = 0; i < 200; ++i) {
154 AddLocal(function, kAstI32);
155 }
156 function->EditVarIntImmediate(offset, 200);
157
158 WasmFunctionEncoder* f = function->Build(&zone, builder);
159 ZoneVector<uint8_t> buffer_vector(f->HeaderSize() + f->BodySize(), &zone);
160 byte* buffer = &buffer_vector[0];
161 byte* header = buffer;
162 byte* body = buffer + f->HeaderSize();
163 f->Serialize(buffer, &header, &body);
164 body = buffer + f->HeaderSize();
165
166 CHECK_EQ(f->BodySize(), 479);
167 const uint8_t varint200_low = (200 & 0x7f) | 0x80;
168 const uint8_t varint200_high = (200 >> 7) & 0x7f;
169 offset = 0;
170 CHECK_EQ(body[offset++], 1); // Local decl count.
171 CHECK_EQ(body[offset++], varint200_low);
172 CHECK_EQ(body[offset++], varint200_high);
173 CHECK_EQ(body[offset++], kLocalI32);
174 CHECK_EQ(body[offset++], kExprBlock);
175 CHECK_EQ(body[offset++], varint200_low);
176 CHECK_EQ(body[offset++], varint200_high);
177 // GetLocal with one-byte indices.
178 for (int i = 0; i <= 127; ++i) {
179 CHECK_EQ(body[offset++], kExprGetLocal);
180 CHECK_EQ(body[offset++], i);
181 }
182 // GetLocal with two-byte indices.
183 for (int i = 128; i < 200; ++i) {
184 CHECK_EQ(body[offset++], kExprGetLocal);
185 CHECK_EQ(body[offset++], (i & 0x7f) | 0x80);
186 CHECK_EQ(body[offset++], (i >> 7) & 0x7f);
187 }
188 CHECK_EQ(offset, 479);
189}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190
191TEST_F(EncoderTest, LEB_Functions) {
192 byte leb_value[5] = {0, 0, 0, 0, 0};
193 CheckReadValue(leb_value, 0, 1, kNoError);
194 CheckWriteValue(0, 1, leb_value);
195 leb_value[0] = 23;
196 CheckReadValue(leb_value, 23, 1, kNoError);
197 CheckWriteValue(23, 1, leb_value);
198 leb_value[0] = 0x80;
199 leb_value[1] = 0x01;
200 CheckReadValue(leb_value, 128, 2, kNoError);
201 CheckWriteValue(128, 2, leb_value);
202 leb_value[0] = 0x80;
203 leb_value[1] = 0x80;
204 leb_value[2] = 0x80;
205 leb_value[3] = 0x80;
206 leb_value[4] = 0x01;
207 CheckReadValue(leb_value, 0x10000000, 5, kNoError);
208 CheckWriteValue(0x10000000, 5, leb_value);
209 leb_value[0] = 0x80;
210 leb_value[1] = 0x80;
211 leb_value[2] = 0x80;
212 leb_value[3] = 0x80;
213 leb_value[4] = 0x80;
214 CheckReadValue(leb_value, -1, -1, kInvalidLEB128);
215}
216} // namespace wasm
217} // namespace internal
218} // namespace v8