Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(603)

Side by Side Diff: test/unittests/wasm/module-decoder-unittest.cc

Issue 1900153002: [wasm] Enforce strict ordering of WASM module sections. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "test/unittests/test-utils.h" 5 #include "test/unittests/test-utils.h"
6 6
7 #include "src/wasm/module-decoder.h" 7 #include "src/wasm/module-decoder.h"
8 #include "src/wasm/wasm-macro-gen.h" 8 #include "src/wasm/wasm-macro-gen.h"
9 #include "src/wasm/wasm-opcodes.h" 9 #include "src/wasm/wasm-opcodes.h"
10 10
11 namespace v8 { 11 namespace v8 {
12 namespace internal { 12 namespace internal {
13 namespace wasm { 13 namespace wasm {
14 14
15 #define EMPTY_FUNCTION(sig_index) 0, SIG_INDEX(sig_index), U16_LE(0) 15 #define EMPTY_FUNCTION(sig_index) 0, SIG_INDEX(sig_index), U16_LE(0)
16 #define EMPTY_FUNCTION_SIZE ((size_t)5) 16 #define EMPTY_FUNCTION_SIZE ((size_t)5)
17 #define EMPTY_BODY 0 17 #define EMPTY_BODY 0
18 #define EMPTY_BODY_SIZE ((size_t)1) 18 #define EMPTY_BODY_SIZE ((size_t)1)
19 #define NOP_BODY 2, 0, kExprNop 19 #define NOP_BODY 2, 0, kExprNop
20 #define NOP_BODY_SIZE ((size_t)3) 20 #define NOP_BODY_SIZE ((size_t)3)
21 #define VOID_VOID_SIG 0, kLocalVoid 21 #define VOID_VOID_SIG 0, kLocalVoid
22 #define VOID_VOID_SIG_SIZE ((size_t)2) 22 #define VOID_VOID_SIG_SIZE ((size_t)2)
23 #define INT_INT_SIG 1, kLocalI32, kLocalI32 23 #define INT_INT_SIG 1, kLocalI32, kLocalI32
24 #define INT_INT_SIG_SIZE ((size_t)3) 24 #define INT_INT_SIG_SIZE ((size_t)3)
25 25
26 // TODO(titzer): tricky size logic! Remove -1.
26 #define SECTION(NAME, EXTRA_SIZE) \ 27 #define SECTION(NAME, EXTRA_SIZE) \
27 U32V_1(WASM_SECTION_##NAME##_SIZE + (EXTRA_SIZE)), WASM_SECTION_##NAME 28 U32V_1(WASM_SECTION_##NAME##_SIZE + (EXTRA_SIZE)), WASM_SECTION_##NAME
28 29
29 #define EXPECT_VERIFIES(data) \ 30 #define EXPECT_VERIFIES(data) \
30 do { \ 31 do { \
31 ModuleResult result = DecodeModule(data, data + arraysize(data)); \ 32 ModuleResult result = DecodeModule(data, data + arraysize(data)); \
32 EXPECT_TRUE(result.ok()); \ 33 EXPECT_TRUE(result.ok()); \
33 if (result.val) delete result.val; \ 34 if (result.val) delete result.val; \
34 } while (false) 35 } while (false)
35 36
36 #define EXPECT_FAILURE_LEN(data, length) \ 37 #define EXPECT_FAILURE_LEN(data, length) \
37 do { \ 38 do { \
38 ModuleResult result = DecodeModule(data, data + length); \ 39 ModuleResult result = DecodeModule(data, data + length); \
39 EXPECT_FALSE(result.ok()); \ 40 EXPECT_FALSE(result.ok()); \
40 if (result.val) delete result.val; \ 41 if (result.val) delete result.val; \
41 } while (false) 42 } while (false)
42 43
43 #define EXPECT_FAILURE(data) EXPECT_FAILURE_LEN(data, sizeof(data)) 44 #define EXPECT_FAILURE(data) EXPECT_FAILURE_LEN(data, sizeof(data))
44 45
45 #define EXPECT_OFF_END_FAILURE(data, min, max) \ 46 #define EXPECT_OFF_END_FAILURE(data, min, max) \
46 do { \ 47 do { \
47 for (size_t length = min; length < max; length++) { \ 48 for (size_t length = min; length < max; length++) { \
48 EXPECT_FAILURE_LEN(data, length); \ 49 EXPECT_FAILURE_LEN(data, length); \
49 } \ 50 } \
50 } while (false) 51 } while (false)
51 52
53 #define EXPECT_OK(result) \
54 do { \
55 EXPECT_TRUE(result.ok()); \
56 if (!result.ok()) { \
57 if (result.val) delete result.val; \
58 return; \
59 } \
60 } while (false)
61
52 static size_t SizeOfVarInt(size_t value) { 62 static size_t SizeOfVarInt(size_t value) {
53 size_t size = 0; 63 size_t size = 0;
54 do { 64 do {
55 size++; 65 size++;
56 value = value >> 7; 66 value = value >> 7;
57 } while (value > 0); 67 } while (value > 0);
58 return size; 68 return size;
59 } 69 }
60 70
61 struct LocalTypePair { 71 struct LocalTypePair {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 } 118 }
109 } 119 }
110 120
111 TEST_F(WasmModuleVerifyTest, DecodeEmpty) { 121 TEST_F(WasmModuleVerifyTest, DecodeEmpty) {
112 static const byte data[] = {SECTION(END, 0)}; 122 static const byte data[] = {SECTION(END, 0)};
113 EXPECT_VERIFIES(data); 123 EXPECT_VERIFIES(data);
114 } 124 }
115 125
116 TEST_F(WasmModuleVerifyTest, OneGlobal) { 126 TEST_F(WasmModuleVerifyTest, OneGlobal) {
117 static const byte data[] = { 127 static const byte data[] = {
118 SECTION(GLOBALS, 7), // -- 128 SECTION(GLOBALS, 5), // --
119 1, 129 1,
120 NAME_LENGTH(1), 130 NAME_LENGTH(1),
121 'g', // name 131 'g', // name
122 kMemI32, // memory type 132 kMemI32, // memory type
123 0, // exported 133 0, // exported
124 }; 134 };
125 135
126 { 136 {
127 // Should decode to exactly one global. 137 // Should decode to exactly one global.
128 ModuleResult result = DecodeModule(data, data + arraysize(data)); 138 ModuleResult result = DecodeModule(data, data + arraysize(data));
129 EXPECT_TRUE(result.ok()); 139 EXPECT_OK(result);
130 EXPECT_EQ(1, result.val->globals.size()); 140 EXPECT_EQ(1, result.val->globals.size());
131 EXPECT_EQ(0, result.val->functions.size()); 141 EXPECT_EQ(0, result.val->functions.size());
132 EXPECT_EQ(0, result.val->data_segments.size()); 142 EXPECT_EQ(0, result.val->data_segments.size());
133 143
134 WasmGlobal* global = &result.val->globals.back(); 144 WasmGlobal* global = &result.val->globals.back();
135 145
136 EXPECT_EQ(1, global->name_length); 146 EXPECT_EQ(1, global->name_length);
137 EXPECT_EQ(MachineType::Int32(), global->type); 147 EXPECT_EQ(MachineType::Int32(), global->type);
138 EXPECT_EQ(0, global->offset); 148 EXPECT_EQ(0, global->offset);
139 EXPECT_FALSE(global->exported); 149 EXPECT_FALSE(global->exported);
140 150
141 if (result.val) delete result.val; 151 if (result.val) delete result.val;
142 } 152 }
143 153
144 EXPECT_OFF_END_FAILURE(data, 1, sizeof(data)); 154 EXPECT_OFF_END_FAILURE(data, 1, sizeof(data));
145 } 155 }
146 156
147 157
148 TEST_F(WasmModuleVerifyTest, ZeroGlobals) { 158 TEST_F(WasmModuleVerifyTest, ZeroGlobals) {
149 static const byte data[] = { 159 static const byte data[] = {
150 SECTION(GLOBALS, 1), // -- 160 SECTION(GLOBALS, 1), // --
151 0, // declare 0 globals 161 0, // declare 0 globals
152 }; 162 };
153 ModuleResult result = DecodeModule(data, data + arraysize(data)); 163 ModuleResult result = DecodeModule(data, data + arraysize(data));
154 EXPECT_TRUE(result.ok()); 164 EXPECT_OK(result);
155 if (result.val) delete result.val; 165 if (result.val) delete result.val;
156 } 166 }
157 167
158 168
159 static void AppendUint32v(std::vector<byte>& buffer, uint32_t val) { 169 static void AppendUint32v(std::vector<byte>& buffer, uint32_t val) {
160 while (true) { 170 while (true) {
161 uint32_t next = val >> 7; 171 uint32_t next = val >> 7;
162 uint32_t out = val & 0x7f; 172 uint32_t out = val & 0x7f;
163 if (next) { 173 if (next) {
164 buffer.push_back(static_cast<byte>(0x80 | out)); 174 buffer.push_back(static_cast<byte>(0x80 | out));
(...skipping 20 matching lines...) Expand all
185 const byte globals[] = {U32V_5(size), WASM_SECTION_GLOBALS}; 195 const byte globals[] = {U32V_5(size), WASM_SECTION_GLOBALS};
186 for (size_t g = 0; g != sizeof(globals); ++g) { 196 for (size_t g = 0; g != sizeof(globals); ++g) {
187 buffer.push_back(globals[g]); 197 buffer.push_back(globals[g]);
188 } 198 }
189 AppendUint32v(buffer, i); // Number of globals. 199 AppendUint32v(buffer, i); // Number of globals.
190 for (uint32_t j = 0; j < i; j++) { 200 for (uint32_t j = 0; j < i; j++) {
191 buffer.insert(buffer.end(), data, data + sizeof(data)); 201 buffer.insert(buffer.end(), data, data + sizeof(data));
192 } 202 }
193 203
194 ModuleResult result = DecodeModule(&buffer[0], &buffer[0] + buffer.size()); 204 ModuleResult result = DecodeModule(&buffer[0], &buffer[0] + buffer.size());
195 EXPECT_TRUE(result.ok()); 205 EXPECT_OK(result);
196 if (result.val) delete result.val; 206 if (result.val) delete result.val;
197 } 207 }
198 } 208 }
199 209
200 TEST_F(WasmModuleVerifyTest, GlobalWithInvalidNameOffset) { 210 TEST_F(WasmModuleVerifyTest, GlobalWithInvalidNameOffset) {
201 static const byte data[] = { 211 static const byte data[] = {
202 SECTION(GLOBALS, 7), 212 SECTION(GLOBALS, 7),
203 1, // declare one global 213 1, // declare one global
204 NO_NAME, // name offset 214 NO_NAME, // name offset
205 33, // memory type 215 33, // memory type
(...skipping 11 matching lines...) Expand all
217 33, // memory type 227 33, // memory type
218 0, // exported 228 0, // exported
219 }; 229 };
220 230
221 EXPECT_FAILURE(data); 231 EXPECT_FAILURE(data);
222 } 232 }
223 233
224 234
225 TEST_F(WasmModuleVerifyTest, TwoGlobals) { 235 TEST_F(WasmModuleVerifyTest, TwoGlobals) {
226 static const byte data[] = { 236 static const byte data[] = {
227 SECTION(GLOBALS, 13), 237 SECTION(GLOBALS, 7),
228 2, 238 2,
229 NO_NAME, // #0: name length 239 NO_NAME, // #0: name length
230 kMemF32, // memory type 240 kMemF32, // memory type
231 0, // exported 241 0, // exported
232 NO_NAME, // #1: name length 242 NO_NAME, // #1: name length
233 kMemF64, // memory type 243 kMemF64, // memory type
234 1, // exported 244 1, // exported
235 }; 245 };
236 246
237 { 247 {
238 // Should decode to exactly two globals. 248 // Should decode to exactly two globals.
239 ModuleResult result = DecodeModule(data, data + arraysize(data)); 249 ModuleResult result = DecodeModule(data, data + arraysize(data));
240 EXPECT_TRUE(result.ok()); 250 EXPECT_OK(result);
241 EXPECT_EQ(2, result.val->globals.size()); 251 EXPECT_EQ(2, result.val->globals.size());
242 EXPECT_EQ(0, result.val->functions.size()); 252 EXPECT_EQ(0, result.val->functions.size());
243 EXPECT_EQ(0, result.val->data_segments.size()); 253 EXPECT_EQ(0, result.val->data_segments.size());
244 254
245 WasmGlobal* g0 = &result.val->globals[0]; 255 WasmGlobal* g0 = &result.val->globals[0];
246 WasmGlobal* g1 = &result.val->globals[1]; 256 WasmGlobal* g1 = &result.val->globals[1];
247 257
248 EXPECT_EQ(0, g0->name_length); 258 EXPECT_EQ(0, g0->name_length);
249 EXPECT_EQ(MachineType::Float32(), g0->type); 259 EXPECT_EQ(MachineType::Float32(), g0->type);
250 EXPECT_EQ(0, g0->offset); 260 EXPECT_EQ(0, g0->offset);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 1, 296 1,
287 kLocalI32, 297 kLocalI32,
288 kLocalF32, // f32 -> i32 298 kLocalF32, // f32 -> i32
289 2, 299 2,
290 kLocalI32, 300 kLocalI32,
291 kLocalF64, 301 kLocalF64,
292 kLocalF64, // (f64,f64) -> i32 302 kLocalF64, // (f64,f64) -> i32
293 }; 303 };
294 304
295 ModuleResult result = DecodeModule(data, data + arraysize(data)); 305 ModuleResult result = DecodeModule(data, data + arraysize(data));
296 EXPECT_TRUE(result.ok()); 306 EXPECT_OK(result);
297 EXPECT_EQ(3, result.val->signatures.size()); 307 EXPECT_EQ(3, result.val->signatures.size());
298 if (result.val->signatures.size() == 3) { 308 if (result.val->signatures.size() == 3) {
299 EXPECT_EQ(0, result.val->signatures[0]->return_count()); 309 EXPECT_EQ(0, result.val->signatures[0]->return_count());
300 EXPECT_EQ(1, result.val->signatures[1]->return_count()); 310 EXPECT_EQ(1, result.val->signatures[1]->return_count());
301 EXPECT_EQ(1, result.val->signatures[2]->return_count()); 311 EXPECT_EQ(1, result.val->signatures[2]->return_count());
302 312
303 EXPECT_EQ(0, result.val->signatures[0]->parameter_count()); 313 EXPECT_EQ(0, result.val->signatures[0]->parameter_count());
304 EXPECT_EQ(1, result.val->signatures[1]->parameter_count()); 314 EXPECT_EQ(1, result.val->signatures[1]->parameter_count());
305 EXPECT_EQ(2, result.val->signatures[2]->parameter_count()); 315 EXPECT_EQ(2, result.val->signatures[2]->parameter_count());
306 } 316 }
(...skipping 27 matching lines...) Expand all
334 344
335 TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) { 345 TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) {
336 const int kCodeStartOffset = 51; 346 const int kCodeStartOffset = 51;
337 const int kCodeEndOffset = kCodeStartOffset + 1; 347 const int kCodeEndOffset = kCodeStartOffset + 1;
338 348
339 static const byte data[] = { 349 static const byte data[] = {
340 SECTION(SIGNATURES, 1 + VOID_VOID_SIG_SIZE), 1, 350 SECTION(SIGNATURES, 1 + VOID_VOID_SIG_SIZE), 1,
341 // sig#0 ------------------------------------------------------- 351 // sig#0 -------------------------------------------------------
342 VOID_VOID_SIG, 352 VOID_VOID_SIG,
343 // func#0 ------------------------------------------------------ 353 // func#0 ------------------------------------------------------
344 SECTION(FUNCTIONS, 19), 1, 354 SECTION(FUNCTIONS, 18), 1,
345 kDeclFunctionLocals | kDeclFunctionExport | kDeclFunctionName, 355 kDeclFunctionLocals | kDeclFunctionExport | kDeclFunctionName,
346 SIG_INDEX(0), // signature index 356 SIG_INDEX(0), // signature index
347 NAME_LENGTH(2), 'h', 'i', // name 357 NAME_LENGTH(2), 'h', 'i', // name
348 U16_LE(1466), // local int32 count 358 U16_LE(1466), // local int32 count
349 U16_LE(1355), // local int64 count 359 U16_LE(1355), // local int64 count
350 U16_LE(1244), // local float32 count 360 U16_LE(1244), // local float32 count
351 U16_LE(1133), // local float64 count 361 U16_LE(1133), // local float64 count
352 1, 0, // size 362 1, 0, // size
353 kExprNop, 363 kExprNop,
354 }; 364 };
355 365
356 { 366 {
357 // Should decode to exactly one function. 367 // Should decode to exactly one function.
358 ModuleResult result = DecodeModule(data, data + arraysize(data)); 368 ModuleResult result = DecodeModule(data, data + arraysize(data));
359 EXPECT_TRUE(result.ok()); 369 EXPECT_OK(result);
360 EXPECT_EQ(0, result.val->globals.size()); 370 EXPECT_EQ(0, result.val->globals.size());
361 EXPECT_EQ(1, result.val->signatures.size()); 371 EXPECT_EQ(1, result.val->signatures.size());
362 EXPECT_EQ(1, result.val->functions.size()); 372 EXPECT_EQ(1, result.val->functions.size());
363 EXPECT_EQ(0, result.val->data_segments.size()); 373 EXPECT_EQ(0, result.val->data_segments.size());
364 EXPECT_EQ(0, result.val->function_table.size()); 374 EXPECT_EQ(0, result.val->function_table.size());
365 375
366 WasmFunction* function = &result.val->functions.back(); 376 WasmFunction* function = &result.val->functions.back();
367 377
368 EXPECT_EQ(39, function->name_offset); 378 EXPECT_EQ(39, function->name_offset);
369 EXPECT_EQ(2, function->name_length); 379 EXPECT_EQ(2, function->name_length);
(...skipping 12 matching lines...) Expand all
382 } 392 }
383 393
384 EXPECT_OFF_END_FAILURE(data, 16, sizeof(data)); 394 EXPECT_OFF_END_FAILURE(data, 16, sizeof(data));
385 } 395 }
386 396
387 397
388 TEST_F(WasmModuleVerifyTest, OneFunctionImported) { 398 TEST_F(WasmModuleVerifyTest, OneFunctionImported) {
389 static const byte data[] = { 399 static const byte data[] = {
390 SECTION(SIGNATURES, VOID_VOID_SIG_SIZE), 1, 400 SECTION(SIGNATURES, VOID_VOID_SIG_SIZE), 1,
391 // sig#0 ------------------------------------------------------- 401 // sig#0 -------------------------------------------------------
392 VOID_VOID_SIG, SECTION(FUNCTIONS, 6), 1, 402 VOID_VOID_SIG, SECTION(FUNCTIONS, 4), 1,
393 // func#0 ------------------------------------------------------ 403 // func#0 ------------------------------------------------------
394 kDeclFunctionImport, // no name, no locals, imported 404 kDeclFunctionImport, // no name, no locals, imported
395 SIG_INDEX(0), 405 SIG_INDEX(0),
396 }; 406 };
397 407
398 ModuleResult result = DecodeModule(data, data + arraysize(data)); 408 ModuleResult result = DecodeModule(data, data + arraysize(data));
399 EXPECT_TRUE(result.ok()); 409 EXPECT_OK(result);
400 EXPECT_EQ(1, result.val->functions.size()); 410 EXPECT_EQ(1, result.val->functions.size());
401 WasmFunction* function = &result.val->functions.back(); 411 WasmFunction* function = &result.val->functions.back();
402 412
403 EXPECT_EQ(0, function->name_length); 413 EXPECT_EQ(0, function->name_length);
404 EXPECT_EQ(0, function->code_start_offset); 414 EXPECT_EQ(0, function->code_start_offset);
405 EXPECT_EQ(0, function->code_end_offset); 415 EXPECT_EQ(0, function->code_end_offset);
406 416
407 EXPECT_EQ(0, function->local_i32_count); 417 EXPECT_EQ(0, function->local_i32_count);
408 EXPECT_EQ(0, function->local_i64_count); 418 EXPECT_EQ(0, function->local_i64_count);
409 EXPECT_EQ(0, function->local_f32_count); 419 EXPECT_EQ(0, function->local_f32_count);
(...skipping 15 matching lines...) Expand all
425 0, 0, // void -> void 435 0, 0, // void -> void
426 SECTION(FUNCTIONS, 7), 1, 436 SECTION(FUNCTIONS, 7), 1,
427 // func#0 ------------------------------------------------------ 437 // func#0 ------------------------------------------------------
428 0, // no name, no locals 438 0, // no name, no locals
429 0, 0, // signature index 439 0, 0, // signature index
430 1, 0, // body size 440 1, 0, // body size
431 kExprNop // body 441 kExprNop // body
432 }; 442 };
433 443
434 ModuleResult result = DecodeModule(data, data + arraysize(data)); 444 ModuleResult result = DecodeModule(data, data + arraysize(data));
435 EXPECT_TRUE(result.ok()); 445 EXPECT_OK(result);
436 EXPECT_EQ(1, result.val->functions.size()); 446 EXPECT_EQ(1, result.val->functions.size());
437 WasmFunction* function = &result.val->functions.back(); 447 WasmFunction* function = &result.val->functions.back();
438 448
439 EXPECT_EQ(0, function->name_length); 449 EXPECT_EQ(0, function->name_length);
440 EXPECT_EQ(kCodeStartOffset, function->code_start_offset); 450 EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
441 EXPECT_EQ(kCodeEndOffset, function->code_end_offset); 451 EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
442 452
443 EXPECT_EQ(0, function->local_i32_count); 453 EXPECT_EQ(0, function->local_i32_count);
444 EXPECT_EQ(0, function->local_i64_count); 454 EXPECT_EQ(0, function->local_i64_count);
445 EXPECT_EQ(0, function->local_f32_count); 455 EXPECT_EQ(0, function->local_f32_count);
(...skipping 19 matching lines...) Expand all
465 kDeclFunctionLocals, 0, 0, // signature index 475 kDeclFunctionLocals, 0, 0, // signature index
466 1, 2, // local int32 count 476 1, 2, // local int32 count
467 3, 4, // local int64 count 477 3, 4, // local int64 count
468 5, 6, // local float32 count 478 5, 6, // local float32 count
469 7, 8, // local float64 count 479 7, 8, // local float64 count
470 1, 0, // body size 480 1, 0, // body size
471 kExprNop // body 481 kExprNop // body
472 }; 482 };
473 483
474 ModuleResult result = DecodeModule(data, data + arraysize(data)); 484 ModuleResult result = DecodeModule(data, data + arraysize(data));
475 EXPECT_TRUE(result.ok()); 485 EXPECT_OK(result);
476 EXPECT_EQ(1, result.val->functions.size()); 486 EXPECT_EQ(1, result.val->functions.size());
477 WasmFunction* function = &result.val->functions.back(); 487 WasmFunction* function = &result.val->functions.back();
478 488
479 EXPECT_EQ(0, function->name_length); 489 EXPECT_EQ(0, function->name_length);
480 EXPECT_EQ(kCodeStartOffset, function->code_start_offset); 490 EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
481 EXPECT_EQ(kCodeEndOffset, function->code_end_offset); 491 EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
482 492
483 EXPECT_EQ(513, function->local_i32_count); 493 EXPECT_EQ(513, function->local_i32_count);
484 EXPECT_EQ(1027, function->local_i64_count); 494 EXPECT_EQ(1027, function->local_i64_count);
485 EXPECT_EQ(1541, function->local_f32_count); 495 EXPECT_EQ(1541, function->local_f32_count);
486 EXPECT_EQ(2055, function->local_f64_count); 496 EXPECT_EQ(2055, function->local_f64_count);
487 497
488 EXPECT_FALSE(function->exported); 498 EXPECT_FALSE(function->exported);
489 EXPECT_FALSE(function->external); 499 EXPECT_FALSE(function->external);
490 500
491 if (result.val) delete result.val; 501 if (result.val) delete result.val;
492 } 502 }
493 503
494 504
495 TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) { 505 TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) {
496 static const byte kCodeStartOffset = 75; 506 static const byte kCodeStartOffset = 64;
497 static const byte kCodeEndOffset = kCodeStartOffset + 3; 507 static const byte kCodeEndOffset = kCodeStartOffset + 3;
498 static const byte kDataSegmentSourceOffset = kCodeEndOffset + 20; 508 static const byte kDataSegmentSourceOffset = kCodeEndOffset + 31;
499 509
500 static const byte data[] = { 510 static const byte data[] = {
501 SECTION(MEMORY, 3), 28, 28, 1,
502 // global#0 -------------------------------------------------- 511 // global#0 --------------------------------------------------
503 SECTION(GLOBALS, 7), 1, 512 SECTION(GLOBALS, 4), 1,
504 0, // name length 513 0, // name length
505 kMemU8, // memory type 514 kMemU8, // memory type
506 0, // exported 515 0, // exported
507 // sig#0 ----------------------------------------------------- 516 // sig#0 -----------------------------------------------------
508 SECTION(SIGNATURES, 3), 1, 0, 0, // void -> void 517 SECTION(SIGNATURES, 3), 1, 0, 0, // void -> void
509 // func#0 ---------------------------------------------------- 518 // func#0 ----------------------------------------------------
510 SECTION(FUNCTIONS, 20), 1, kDeclFunctionLocals | kDeclFunctionName, 0, 519 SECTION(FUNCTIONS, 20), 1,
511 0, // signature index 520 kDeclFunctionLocals | kDeclFunctionName, // --
512 2, 'h', 'i', // name 521 SIG_INDEX(0), // signature index
513 1, 2, // local int32 count 522 2, 'h', 'i', // name
514 3, 4, // local int64 count 523 1, 2, // local int32 count
515 5, 6, // local float32 count 524 3, 4, // local int64 count
516 7, 8, // local float64 count 525 5, 6, // local float32 count
517 3, 0, // body size 526 7, 8, // local float64 count
518 kExprNop, // func#0 body 527 3, 0, // body size
519 kExprNop, // func#0 body 528 kExprNop, // func#0 body
520 kExprNop, // func#0 body 529 kExprNop, // func#0 body
530 kExprNop, // func#0 body
531 // memory section --------------------------------------------
532 SECTION(MEMORY, 3), 28, 28, 1,
521 // segment#0 ------------------------------------------------- 533 // segment#0 -------------------------------------------------
522 SECTION(DATA_SEGMENTS, 14), 1, 534 SECTION(DATA_SEGMENTS, 14), 1,
523 U32V_3(0x8b3ae), // dest addr 535 U32V_3(0x8b3ae), // dest addr
524 U32V_1(5), // source size 536 U32V_1(5), // source size
525 0, 1, 2, 3, 4, // data bytes 537 0, 1, 2, 3, 4, // data bytes
526 // rest ------------------------------------------------------ 538 // rest ------------------------------------------------------
527 SECTION(END, 0), 539 SECTION(END, 0),
528 }; 540 };
529 541
530 { 542 {
531 ModuleResult result = DecodeModule(data, data + arraysize(data)); 543 ModuleResult result = DecodeModule(data, data + arraysize(data));
532 EXPECT_TRUE(result.ok()); 544 EXPECT_OK(result);
533 EXPECT_EQ(1, result.val->globals.size()); 545 EXPECT_EQ(1, result.val->globals.size());
534 EXPECT_EQ(1, result.val->functions.size()); 546 EXPECT_EQ(1, result.val->functions.size());
535 EXPECT_EQ(1, result.val->data_segments.size()); 547 EXPECT_EQ(1, result.val->data_segments.size());
536 548
537 WasmGlobal* global = &result.val->globals.back(); 549 WasmGlobal* global = &result.val->globals.back();
538 550
539 EXPECT_EQ(0, global->name_length); 551 EXPECT_EQ(0, global->name_length);
540 EXPECT_EQ(MachineType::Uint8(), global->type); 552 EXPECT_EQ(MachineType::Uint8(), global->type);
541 EXPECT_EQ(0, global->offset); 553 EXPECT_EQ(0, global->offset);
542 EXPECT_FALSE(global->exported); 554 EXPECT_FALSE(global->exported);
543 555
544 WasmFunction* function = &result.val->functions.back(); 556 WasmFunction* function = &result.val->functions.back();
545 557
546 EXPECT_EQ(63, function->name_offset); 558 EXPECT_EQ(52, function->name_offset);
547 EXPECT_EQ(2, function->name_length); 559 EXPECT_EQ(2, function->name_length);
548 EXPECT_EQ(kCodeStartOffset, function->code_start_offset); 560 EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
549 EXPECT_EQ(kCodeEndOffset, function->code_end_offset); 561 EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
550 562
551 EXPECT_FALSE(function->exported); 563 EXPECT_FALSE(function->exported);
552 EXPECT_FALSE(function->external); 564 EXPECT_FALSE(function->external);
553 565
554 WasmDataSegment* segment = &result.val->data_segments.back(); 566 WasmDataSegment* segment = &result.val->data_segments.back();
555 567
556 EXPECT_EQ(0x8b3ae, segment->dest_addr); 568 EXPECT_EQ(0x8b3ae, segment->dest_addr);
(...skipping 18 matching lines...) Expand all
575 U32V_3(0x9bbaa), // dest addr 587 U32V_3(0x9bbaa), // dest addr
576 U32V_1(3), // source size 588 U32V_1(3), // source size
577 'a', 589 'a',
578 'b', 590 'b',
579 'c' // data bytes 591 'c' // data bytes
580 }; 592 };
581 593
582 { 594 {
583 EXPECT_VERIFIES(data); 595 EXPECT_VERIFIES(data);
584 ModuleResult result = DecodeModule(data, data + arraysize(data)); 596 ModuleResult result = DecodeModule(data, data + arraysize(data));
585 EXPECT_TRUE(result.ok()); 597 EXPECT_OK(result);
586 EXPECT_EQ(0, result.val->globals.size()); 598 EXPECT_EQ(0, result.val->globals.size());
587 EXPECT_EQ(0, result.val->functions.size()); 599 EXPECT_EQ(0, result.val->functions.size());
588 EXPECT_EQ(1, result.val->data_segments.size()); 600 EXPECT_EQ(1, result.val->data_segments.size());
589 601
590 WasmDataSegment* segment = &result.val->data_segments.back(); 602 WasmDataSegment* segment = &result.val->data_segments.back();
591 603
592 EXPECT_EQ(0x9bbaa, segment->dest_addr); 604 EXPECT_EQ(0x9bbaa, segment->dest_addr);
593 EXPECT_EQ(kDataSegmentSourceOffset, segment->source_offset); 605 EXPECT_EQ(kDataSegmentSourceOffset, segment->source_offset);
594 EXPECT_EQ(3, segment->source_size); 606 EXPECT_EQ(3, segment->source_size);
595 EXPECT_TRUE(segment->init); 607 EXPECT_TRUE(segment->init);
596 608
597 if (result.val) delete result.val; 609 if (result.val) delete result.val;
598 } 610 }
599 611
600 EXPECT_OFF_END_FAILURE(data, 13, sizeof(data)); 612 EXPECT_OFF_END_FAILURE(data, 13, sizeof(data));
601 } 613 }
602 614
603 615
604 TEST_F(WasmModuleVerifyTest, TwoDataSegments) { 616 TEST_F(WasmModuleVerifyTest, TwoDataSegments) {
605 const byte kDataSegment0SourceOffset = 39; 617 const byte kDataSegment0SourceOffset = 39;
606 const byte kDataSegment1SourceOffset = 39 + 8; 618 const byte kDataSegment1SourceOffset = 39 + 8;
607 619
608 const byte data[] = { 620 const byte data[] = {
609 SECTION(MEMORY, 3), 621 SECTION(MEMORY, 3),
610 28, 622 28,
611 28, 623 28,
612 1, 624 1,
613 SECTION(DATA_SEGMENTS, 31), 625 SECTION(DATA_SEGMENTS, 23),
614 2, // segment count 626 2, // segment count
615 U32V_3(0x7ffee), // #0: dest addr 627 U32V_3(0x7ffee), // #0: dest addr
616 U32V_1(4), // source size 628 U32V_1(4), // source size
617 1, 629 1,
618 2, 630 2,
619 3, 631 3,
620 4, // data bytes 632 4, // data bytes
621 U32V_3(0x6ddcc), // #1: dest addr 633 U32V_3(0x6ddcc), // #1: dest addr
622 U32V_1(10), // source size 634 U32V_1(10), // source size
623 1, 635 1,
624 2, 636 2,
625 3, 637 3,
626 4, 638 4,
627 5, 639 5,
628 6, 640 6,
629 7, 641 7,
630 8, 642 8,
631 9, 643 9,
632 10 // data bytes 644 10 // data bytes
633 }; 645 };
634 646
635 { 647 {
636 ModuleResult result = DecodeModule(data, data + arraysize(data)); 648 ModuleResult result = DecodeModule(data, data + arraysize(data));
637 EXPECT_TRUE(result.ok()); 649 EXPECT_OK(result);
638 EXPECT_EQ(0, result.val->globals.size()); 650 EXPECT_EQ(0, result.val->globals.size());
639 EXPECT_EQ(0, result.val->functions.size()); 651 EXPECT_EQ(0, result.val->functions.size());
640 EXPECT_EQ(2, result.val->data_segments.size()); 652 EXPECT_EQ(2, result.val->data_segments.size());
641 653
642 WasmDataSegment* s0 = &result.val->data_segments[0]; 654 WasmDataSegment* s0 = &result.val->data_segments[0];
643 WasmDataSegment* s1 = &result.val->data_segments[1]; 655 WasmDataSegment* s1 = &result.val->data_segments[1];
644 656
645 EXPECT_EQ(0x7ffee, s0->dest_addr); 657 EXPECT_EQ(0x7ffee, s0->dest_addr);
646 EXPECT_EQ(kDataSegment0SourceOffset, s0->source_offset); 658 EXPECT_EQ(kDataSegment0SourceOffset, s0->source_offset);
647 EXPECT_EQ(4, s0->source_size); 659 EXPECT_EQ(4, s0->source_size);
(...skipping 15 matching lines...) Expand all
663 675
664 for (byte mem_pages = 1; mem_pages < 16; mem_pages++) { 676 for (byte mem_pages = 1; mem_pages < 16; mem_pages++) {
665 int mem_size = mem_pages * 0x10000; // 64k pages. 677 int mem_size = mem_pages * 0x10000; // 64k pages.
666 678
667 for (int dest_addr = mem_size - source_size; 679 for (int dest_addr = mem_size - source_size;
668 dest_addr < mem_size + source_size; dest_addr++) { 680 dest_addr < mem_size + source_size; dest_addr++) {
669 byte data[] = {SECTION(MEMORY, 3), 681 byte data[] = {SECTION(MEMORY, 3),
670 mem_pages, 682 mem_pages,
671 mem_pages, 683 mem_pages,
672 1, 684 1,
673 SECTION(DATA_SEGMENTS, 14), 685 SECTION(DATA_SEGMENTS, 8),
674 1, 686 1,
675 U32V_3(dest_addr), 687 U32V_3(dest_addr),
676 U32V_1(source_size), 688 U32V_1(source_size),
677 'a', 689 'a',
678 'b', 690 'b',
679 'c'}; 691 'c'};
680 692
681 if (dest_addr <= (mem_size - source_size)) { 693 if (dest_addr <= (mem_size - source_size)) {
682 EXPECT_VERIFIES(data); 694 EXPECT_VERIFIES(data);
683 } else { 695 } else {
(...skipping 10 matching lines...) Expand all
694 TEST_F(WasmModuleVerifyTest, OneIndirectFunction) { 706 TEST_F(WasmModuleVerifyTest, OneIndirectFunction) {
695 static const byte data[] = { 707 static const byte data[] = {
696 // sig#0 ------------------------------------------------------- 708 // sig#0 -------------------------------------------------------
697 SECTION(SIGNATURES, 3), 1, 0, 0, // void -> void 709 SECTION(SIGNATURES, 3), 1, 0, 0, // void -> void
698 // func#0 ------------------------------------------------------ 710 // func#0 ------------------------------------------------------
699 SECTION(FUNCTIONS, 4), 1, FUNCTION(0, 0), 711 SECTION(FUNCTIONS, 4), 1, FUNCTION(0, 0),
700 // indirect table ---------------------------------------------- 712 // indirect table ----------------------------------------------
701 SECTION(FUNCTION_TABLE, 2), 1, U32V_1(0)}; 713 SECTION(FUNCTION_TABLE, 2), 1, U32V_1(0)};
702 714
703 ModuleResult result = DecodeModule(data, data + arraysize(data)); 715 ModuleResult result = DecodeModule(data, data + arraysize(data));
704 EXPECT_TRUE(result.ok()); 716 EXPECT_OK(result);
705 if (result.ok()) { 717 if (result.ok()) {
706 EXPECT_EQ(1, result.val->signatures.size()); 718 EXPECT_EQ(1, result.val->signatures.size());
707 EXPECT_EQ(1, result.val->functions.size()); 719 EXPECT_EQ(1, result.val->functions.size());
708 EXPECT_EQ(1, result.val->function_table.size()); 720 EXPECT_EQ(1, result.val->function_table.size());
709 EXPECT_EQ(0, result.val->function_table[0]); 721 EXPECT_EQ(0, result.val->function_table[0]);
710 } 722 }
711 if (result.val) delete result.val; 723 if (result.val) delete result.val;
712 } 724 }
713 725
714 726
(...skipping 13 matching lines...) Expand all
728 U32V_1(1), // -- 740 U32V_1(1), // --
729 U32V_1(2), // -- 741 U32V_1(2), // --
730 U32V_1(3), // -- 742 U32V_1(3), // --
731 U32V_1(0), // -- 743 U32V_1(0), // --
732 U32V_1(1), // -- 744 U32V_1(1), // --
733 U32V_1(2), // -- 745 U32V_1(2), // --
734 U32V_1(3), // -- 746 U32V_1(3), // --
735 }; 747 };
736 748
737 ModuleResult result = DecodeModule(data, data + arraysize(data)); 749 ModuleResult result = DecodeModule(data, data + arraysize(data));
738 EXPECT_TRUE(result.ok()); 750 EXPECT_OK(result);
739 if (result.ok()) { 751 if (result.ok()) {
740 EXPECT_EQ(2, result.val->signatures.size()); 752 EXPECT_EQ(2, result.val->signatures.size());
741 EXPECT_EQ(4, result.val->functions.size()); 753 EXPECT_EQ(4, result.val->functions.size());
742 EXPECT_EQ(8, result.val->function_table.size()); 754 EXPECT_EQ(8, result.val->function_table.size());
743 for (int i = 0; i < 8; i++) { 755 for (int i = 0; i < 8; i++) {
744 EXPECT_EQ(i & 3, result.val->function_table[i]); 756 EXPECT_EQ(i & 3, result.val->function_table[i]);
745 } 757 }
746 } 758 }
747 if (result.val) delete result.val; 759 if (result.val) delete result.val;
748 } 760 }
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 4, // locals 921 4, // locals
910 3, kLocalI32, // -- 922 3, kLocalI32, // --
911 4, kLocalI64, // -- 923 4, kLocalI64, // --
912 5, kLocalF32, // -- 924 5, kLocalF32, // --
913 6, kLocalF64, // -- 925 6, kLocalF64, // --
914 kExprNop // body 926 kExprNop // body
915 }; 927 };
916 928
917 FunctionResult result = DecodeWasmFunction(isolate(), zone(), nullptr, data, 929 FunctionResult result = DecodeWasmFunction(isolate(), zone(), nullptr, data,
918 data + arraysize(data)); 930 data + arraysize(data));
919 EXPECT_TRUE(result.ok()); 931 EXPECT_OK(result);
920 932
921 if (result.val && result.ok()) { 933 if (result.val && result.ok()) {
922 WasmFunction* function = result.val; 934 WasmFunction* function = result.val;
923 EXPECT_EQ(0, function->sig->parameter_count()); 935 EXPECT_EQ(0, function->sig->parameter_count());
924 EXPECT_EQ(0, function->sig->return_count()); 936 EXPECT_EQ(0, function->sig->return_count());
925 EXPECT_EQ(0, function->name_offset); 937 EXPECT_EQ(0, function->name_offset);
926 EXPECT_EQ(2, function->code_start_offset); 938 EXPECT_EQ(2, function->code_start_offset);
927 EXPECT_EQ(arraysize(data), function->code_end_offset); 939 EXPECT_EQ(arraysize(data), function->code_end_offset);
928 // TODO(titzer): verify encoding of local declarations 940 // TODO(titzer): verify encoding of local declarations
929 EXPECT_FALSE(function->external); 941 EXPECT_FALSE(function->external);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 }; 1036 };
1025 EXPECT_FAILURE(data); 1037 EXPECT_FAILURE(data);
1026 } 1038 }
1027 1039
1028 TEST_F(WasmModuleVerifyTest, UnknownSectionSkipped) { 1040 TEST_F(WasmModuleVerifyTest, UnknownSectionSkipped) {
1029 static const byte data[] = { 1041 static const byte data[] = {
1030 3, // Section size. 1042 3, // Section size.
1031 1, 1043 1,
1032 '\0', // Section name: LEB128 1, string '\0' 1044 '\0', // Section name: LEB128 1, string '\0'
1033 0, // one byte section 1045 0, // one byte section
1034 SECTION(GLOBALS, 7), 1046 SECTION(GLOBALS, 4),
1035 1, 1047 1,
1036 0, // name length 1048 0, // name length
1037 kMemI32, // memory type 1049 kMemI32, // memory type
1038 0, // exported 1050 0, // exported
1039 }; 1051 };
1040 ModuleResult result = DecodeModule(data, data + arraysize(data)); 1052 ModuleResult result = DecodeModule(data, data + arraysize(data));
1041 EXPECT_TRUE(result.ok()); 1053 EXPECT_OK(result);
1042 1054
1043 EXPECT_EQ(1, result.val->globals.size()); 1055 EXPECT_EQ(1, result.val->globals.size());
1044 EXPECT_EQ(0, result.val->functions.size()); 1056 EXPECT_EQ(0, result.val->functions.size());
1045 EXPECT_EQ(0, result.val->data_segments.size()); 1057 EXPECT_EQ(0, result.val->data_segments.size());
1046 1058
1047 WasmGlobal* global = &result.val->globals.back(); 1059 WasmGlobal* global = &result.val->globals.back();
1048 1060
1049 EXPECT_EQ(0, global->name_length); 1061 EXPECT_EQ(0, global->name_length);
1050 EXPECT_EQ(MachineType::Int32(), global->type); 1062 EXPECT_EQ(MachineType::Int32(), global->type);
1051 EXPECT_EQ(0, global->offset); 1063 EXPECT_EQ(0, global->offset);
1052 EXPECT_FALSE(global->exported); 1064 EXPECT_FALSE(global->exported);
1053 1065
1054 if (result.val) delete result.val; 1066 if (result.val) delete result.val;
1055 } 1067 }
1056 1068
1057 TEST_F(WasmModuleVerifyTest, ImportTable_empty) { 1069 TEST_F(WasmModuleVerifyTest, ImportTable_empty) {
1058 static const byte data[] = {SECTION(SIGNATURES, 1), 0, 1070 static const byte data[] = {SECTION(SIGNATURES, 1), 0,
1059 SECTION(IMPORT_TABLE, 1), 0}; 1071 SECTION(IMPORT_TABLE, 1), 0};
1060 EXPECT_VERIFIES(data); 1072 EXPECT_VERIFIES(data);
1061 } 1073 }
1062 1074
1063 TEST_F(WasmModuleVerifyTest, ImportTable_nosigs) { 1075 TEST_F(WasmModuleVerifyTest, ImportTable_nosigs) {
1064 static const byte data[] = {SECTION(IMPORT_TABLE, 1), 0}; 1076 static const byte data[] = {SECTION(IMPORT_TABLE, 1), 0};
1065 EXPECT_FAILURE(data); 1077 EXPECT_VERIFIES(data);
JF 2016/04/19 15:48:47 Hmm, this is now OK?
titzer 2016/04/20 08:51:24 Yeah. It's OK to have an empty import table withou
1066 } 1078 }
1067 1079
1068 TEST_F(WasmModuleVerifyTest, ImportTable_invalid_sig) { 1080 TEST_F(WasmModuleVerifyTest, ImportTable_invalid_sig) {
1069 static const byte data[] = { 1081 static const byte data[] = {
1070 SECTION(SIGNATURES, 1), 0, SECTION(IMPORT_TABLE, 6), 1, 1082 SECTION(SIGNATURES, 1), 0, SECTION(IMPORT_TABLE, 6), 1,
1071 IMPORT_SIG_INDEX(0), // sig index 1083 IMPORT_SIG_INDEX(0), // sig index
1072 NAME_LENGTH(1), 'm', // module name 1084 NAME_LENGTH(1), 'm', // module name
1073 NAME_LENGTH(1), 'f', // function name 1085 NAME_LENGTH(1), 'f', // function name
1074 }; 1086 };
1075 EXPECT_FAILURE(data); 1087 EXPECT_FAILURE(data);
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
1155 } 1167 }
1156 1168
1157 TEST_F(WasmModuleVerifyTest, ExportTableOne) { 1169 TEST_F(WasmModuleVerifyTest, ExportTableOne) {
1158 static const byte data[] = { 1170 static const byte data[] = {
1159 SECTION(SIGNATURES, 1 + VOID_VOID_SIG_SIZE), 1171 SECTION(SIGNATURES, 1 + VOID_VOID_SIG_SIZE),
1160 1, // sigs 1172 1, // sigs
1161 VOID_VOID_SIG, // -- 1173 VOID_VOID_SIG, // --
1162 SECTION(FUNCTIONS, 1 + EMPTY_FUNCTION_SIZE), 1174 SECTION(FUNCTIONS, 1 + EMPTY_FUNCTION_SIZE),
1163 1, // functions 1175 1, // functions
1164 EMPTY_FUNCTION(0), // -- 1176 EMPTY_FUNCTION(0), // --
1165 SECTION(EXPORT_TABLE, 7), 1177 SECTION(EXPORT_TABLE, 3),
1166 1, // exports 1178 1, // exports
1167 FUNC_INDEX(0), // -- 1179 FUNC_INDEX(0), // --
1168 NO_NAME // -- 1180 NO_NAME // --
1169 }; 1181 };
1170 EXPECT_VERIFIES(data); 1182 EXPECT_VERIFIES(data);
1171 } 1183 }
1172 1184
1173 TEST_F(WasmModuleVerifyTest, ExportTableTwo) { 1185 TEST_F(WasmModuleVerifyTest, ExportTableTwo) {
1174 static const byte data[] = { 1186 static const byte data[] = {
1175 SECTION(SIGNATURES, 1 + VOID_VOID_SIG_SIZE), 1187 SECTION(SIGNATURES, 1 + VOID_VOID_SIG_SIZE),
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1368 NO_LOCAL_NAMES, // -- 1380 NO_LOCAL_NAMES, // --
1369 FOO_STRING, 1381 FOO_STRING,
1370 NO_LOCAL_NAMES, // -- 1382 NO_LOCAL_NAMES, // --
1371 }; 1383 };
1372 EXPECT_VERIFIES(data); 1384 EXPECT_VERIFIES(data);
1373 } 1385 }
1374 1386
1375 } // namespace wasm 1387 } // namespace wasm
1376 } // namespace internal 1388 } // namespace internal
1377 } // namespace v8 1389 } // namespace v8
OLDNEW
« test/mjsunit/wasm/wasm-module-builder.js ('K') | « test/mjsunit/wasm/wasm-module-builder.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698