| // Copyright 2019 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. |
| |
| // Flags: --allow-natives-syntax --randomize-all-allocations |
| // Flags: --wasm-max-initial-code-space-reservation=1 |
| |
| // Disable tier-up, to reduce execution time of this test (Liftoff generates |
| // much bigger code, thus reaches the four code spaces much faster). |
| // Flags: --no-wasm-tier-up |
| |
| load('test/mjsunit/wasm/wasm-module-builder.js'); |
| |
| // Instantiate bigger modules, until at least four separate code spaces have |
| // been allocated. |
| // Each function calls through many of the previous functions to execute the |
| // jump table(s) sufficiently. |
| |
| let num_functions = 50; |
| while (true) { |
| print(`Trying ${num_functions} functions...`); |
| if (num_functions > 1e6) { |
| throw new Error('We should have hit four code spaces by now'); |
| } |
| const builder = new WasmModuleBuilder(); |
| builder.addMemory(1, 1, false); |
| builder.addFunction('f0', kSig_i_i).addBody([kExprLocalGet, 0]); |
| // Generate some code per function to fill the code space. |
| // Each function contains a number of loads that will not be executed |
| // (inside an "if (i == 0)" block). They increase the code size a bit so we |
| // do not need too many functions. |
| // Each function f<n> with argument {i} then calls f<n/10> with argument |
| // {i + 1} and returns whatever that function returns. |
| const body_template = [ |
| kExprLocalGet, 0, kExprI32Eqz, kExprIf, kWasmStmt, // if (i == 0) |
| kExprLocalGet, 0 // get i |
| ]; |
| for (let i = 0; i < 1000; ++i) body_template.push(kExprI32LoadMem, 0, 0); |
| body_template.push( |
| kExprDrop, kExprEnd, // end if |
| kExprLocalGet, 0, kExprI32Const, 1, kExprI32Add, // i + 1 |
| kExprCallFunction // call f<?> |
| ); |
| for (let i = 1; i < num_functions; ++i) { |
| const body = body_template.slice(); |
| body.push(...wasmSignedLeb(Math.floor(i / 10))); |
| builder.addFunction('f' + i, kSig_i_i).addBody(body); |
| } |
| builder.addExport('f', num_functions - 1); |
| const instance = builder.instantiate(); |
| let expected = 17; |
| for (let i = num_functions - 1; i > 0; i = Math.floor(i / 10)) ++expected; |
| assertEquals(expected, instance.exports.f(17)); |
| const num_code_spaces = %WasmNumCodeSpaces(instance); |
| print(`--> ${num_code_spaces} code spaces.`); |
| if (num_code_spaces >= 4) break; |
| num_functions *= 2; |
| } |