LCOV - code coverage report
Current view: top level - test/cctest/wasm - test-run-wasm-bulk-memory.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 375 375 100.0 %
Date: 2019-04-17 Functions: 101 101 100.0 %

          Line data    Source code
       1             : // Copyright 2019 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/cctest/cctest.h"
       6             : #include "test/cctest/wasm/wasm-run-utils.h"
       7             : #include "test/common/wasm/test-signatures.h"
       8             : #include "test/common/wasm/wasm-macro-gen.h"
       9             : 
      10             : namespace v8 {
      11             : namespace internal {
      12             : namespace wasm {
      13             : namespace test_run_wasm_bulk_memory {
      14             : 
      15             : namespace {
      16         204 : void CheckMemoryEquals(TestingModuleBuilder& builder, size_t index,
      17             :                        const std::vector<byte>& expected) {
      18             :   const byte* mem_start = builder.raw_mem_start<byte>();
      19             :   const byte* mem_end = builder.raw_mem_end<byte>();
      20         204 :   size_t mem_size = mem_end - mem_start;
      21         204 :   CHECK_LE(index, mem_size);
      22         204 :   CHECK_LE(index + expected.size(), mem_size);
      23        4044 :   for (size_t i = 0; i < expected.size(); ++i) {
      24        3840 :     CHECK_EQ(expected[i], mem_start[index + i]);
      25             :   }
      26         204 : }
      27             : 
      28         156 : void CheckMemoryEqualsZero(TestingModuleBuilder& builder, size_t index,
      29             :                            size_t length) {
      30             :   const byte* mem_start = builder.raw_mem_start<byte>();
      31             :   const byte* mem_end = builder.raw_mem_end<byte>();
      32         156 :   size_t mem_size = mem_end - mem_start;
      33         156 :   CHECK_LE(index, mem_size);
      34         156 :   CHECK_LE(index + length, mem_size);
      35    20444172 :   for (size_t i = 0; i < length; ++i) {
      36    20444016 :     CHECK_EQ(0, mem_start[index + i]);
      37             :   }
      38         156 : }
      39             : 
      40         144 : void CheckMemoryEqualsFollowedByZeroes(TestingModuleBuilder& builder,
      41             :                                        const std::vector<byte>& expected) {
      42         144 :   CheckMemoryEquals(builder, 0, expected);
      43         288 :   CheckMemoryEqualsZero(builder, expected.size(),
      44         144 :                         builder.mem_size() - expected.size());
      45         144 : }
      46             : }  // namespace
      47             : 
      48       26663 : WASM_EXEC_TEST(MemoryInit) {
      49             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
      50          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
      51          12 :   r.builder().AddMemory(kWasmPageSize);
      52          12 :   const byte data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
      53          12 :   r.builder().AddPassiveDataSegment(Vector<const byte>(data));
      54          12 :   BUILD(r,
      55             :         WASM_MEMORY_INIT(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
      56             :                          WASM_GET_LOCAL(2)),
      57             :         kExprI32Const, 0);
      58             : 
      59             :   // All zeroes.
      60          12 :   CheckMemoryEqualsZero(r.builder(), 0, kWasmPageSize);
      61             : 
      62             :   // Copy all bytes from data segment 0, to memory at [10, 20).
      63          12 :   CHECK_EQ(0, r.Call(10, 0, 10));
      64          12 :   CheckMemoryEqualsFollowedByZeroes(
      65             :       r.builder(),
      66          12 :       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
      67             : 
      68             :   // Copy bytes in range [5, 10) from data segment 0, to memory at [0, 5).
      69          12 :   CHECK_EQ(0, r.Call(0, 5, 5));
      70          12 :   CheckMemoryEqualsFollowedByZeroes(
      71             :       r.builder(),
      72          12 :       {5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
      73             : 
      74             :   // Copy 0 bytes does nothing.
      75          12 :   CHECK_EQ(0, r.Call(10, 1, 0));
      76          12 :   CheckMemoryEqualsFollowedByZeroes(
      77             :       r.builder(),
      78          12 :       {5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
      79             : 
      80             :   // Copy 0 at end of memory region or data segment is OK.
      81          12 :   CHECK_EQ(0, r.Call(kWasmPageSize, 0, 0));
      82          12 :   CHECK_EQ(0, r.Call(0, sizeof(data), 0));
      83          12 : }
      84             : 
      85       26663 : WASM_EXEC_TEST(MemoryInitOutOfBoundsData) {
      86             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
      87          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
      88          12 :   r.builder().AddMemory(kWasmPageSize);
      89          12 :   const byte data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
      90          12 :   r.builder().AddPassiveDataSegment(Vector<const byte>(data));
      91          12 :   BUILD(r,
      92             :         WASM_MEMORY_INIT(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
      93             :                          WASM_GET_LOCAL(2)),
      94             :         kExprI32Const, 0);
      95             : 
      96             :   const uint32_t last_5_bytes = kWasmPageSize - 5;
      97             : 
      98             :   // Write all values up to the out-of-bounds write.
      99          12 :   CHECK_EQ(0xDEADBEEF, r.Call(kWasmPageSize - 5, 0, 6));
     100          24 :   CheckMemoryEquals(r.builder(), last_5_bytes, {0, 1, 2, 3, 4});
     101             : 
     102             :   // Write all values up to the out-of-bounds read.
     103             :   r.builder().BlankMemory();
     104          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, 5, 6));
     105          24 :   CheckMemoryEqualsFollowedByZeroes(r.builder(), {5, 6, 7, 8, 9});
     106          12 : }
     107             : 
     108       26663 : WASM_EXEC_TEST(MemoryInitOutOfBounds) {
     109             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     110          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     111          12 :   r.builder().AddMemory(kWasmPageSize);
     112          12 :   const byte data[kWasmPageSize] = {};
     113          12 :   r.builder().AddPassiveDataSegment(Vector<const byte>(data));
     114          12 :   BUILD(r,
     115             :         WASM_MEMORY_INIT(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
     116             :                          WASM_GET_LOCAL(2)),
     117             :         kExprI32Const, 0);
     118             : 
     119             :   // OK, copy the full data segment to memory.
     120          12 :   r.Call(0, 0, kWasmPageSize);
     121             : 
     122             :   // Source range must not be out of bounds.
     123          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, 1, kWasmPageSize));
     124          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, 1000, kWasmPageSize));
     125          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, kWasmPageSize, 1));
     126             : 
     127             :   // Destination range must not be out of bounds.
     128          12 :   CHECK_EQ(0xDEADBEEF, r.Call(1, 0, kWasmPageSize));
     129          12 :   CHECK_EQ(0xDEADBEEF, r.Call(1000, 0, kWasmPageSize));
     130          12 :   CHECK_EQ(0xDEADBEEF, r.Call(kWasmPageSize, 0, 1));
     131             : 
     132             :   // Copy 0 out-of-bounds fails.
     133          12 :   CHECK_EQ(0xDEADBEEF, r.Call(kWasmPageSize + 1, 0, 0));
     134          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, kWasmPageSize + 1, 0));
     135             : 
     136             :   // Make sure bounds aren't checked with 32-bit wrapping.
     137          12 :   CHECK_EQ(0xDEADBEEF, r.Call(1, 1, 0xFFFFFFFF));
     138          12 : }
     139             : 
     140       26663 : WASM_EXEC_TEST(MemoryCopy) {
     141             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     142          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     143          12 :   byte* mem = r.builder().AddMemory(kWasmPageSize);
     144          12 :   BUILD(
     145             :       r,
     146             :       WASM_MEMORY_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     147             :       kExprI32Const, 0);
     148             : 
     149          12 :   const byte initial[] = {0, 11, 22, 33, 44, 55, 66, 77};
     150             :   memcpy(mem, initial, sizeof(initial));
     151             : 
     152             :   // Copy from [1, 8] to [10, 16].
     153          12 :   CHECK_EQ(0, r.Call(10, 1, 8));
     154          12 :   CheckMemoryEqualsFollowedByZeroes(
     155             :       r.builder(),
     156          12 :       {0, 11, 22, 33, 44, 55, 66, 77, 0, 0, 11, 22, 33, 44, 55, 66, 77});
     157             : 
     158             :   // Copy 0 bytes does nothing.
     159          12 :   CHECK_EQ(0, r.Call(10, 2, 0));
     160          12 :   CheckMemoryEqualsFollowedByZeroes(
     161             :       r.builder(),
     162          12 :       {0, 11, 22, 33, 44, 55, 66, 77, 0, 0, 11, 22, 33, 44, 55, 66, 77});
     163             : 
     164             :   // Copy 0 at end of memory region is OK.
     165          12 :   CHECK_EQ(0, r.Call(kWasmPageSize, 0, 0));
     166          12 :   CHECK_EQ(0, r.Call(0, kWasmPageSize, 0));
     167          12 : }
     168             : 
     169       26663 : WASM_EXEC_TEST(MemoryCopyOverlapping) {
     170             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     171          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     172          12 :   byte* mem = r.builder().AddMemory(kWasmPageSize);
     173          12 :   BUILD(
     174             :       r,
     175             :       WASM_MEMORY_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     176             :       kExprI32Const, 0);
     177             : 
     178          12 :   const byte initial[] = {10, 20, 30};
     179             :   memcpy(mem, initial, sizeof(initial));
     180             : 
     181             :   // Copy from [0, 3] -> [2, 5]. The copy must not overwrite 30 before copying
     182             :   // it (i.e. cannot copy forward in this case).
     183          12 :   CHECK_EQ(0, r.Call(2, 0, 3));
     184          24 :   CheckMemoryEqualsFollowedByZeroes(r.builder(), {10, 20, 10, 20, 30});
     185             : 
     186             :   // Copy from [2, 5] -> [0, 3]. The copy must not write the first 10 (i.e.
     187             :   // cannot copy backward in this case).
     188          12 :   CHECK_EQ(0, r.Call(0, 2, 3));
     189          24 :   CheckMemoryEqualsFollowedByZeroes(r.builder(), {10, 20, 30, 20, 30});
     190          12 : }
     191             : 
     192       26663 : WASM_EXEC_TEST(MemoryCopyOutOfBoundsData) {
     193             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     194          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     195          12 :   byte* mem = r.builder().AddMemory(kWasmPageSize);
     196          12 :   BUILD(
     197             :       r,
     198             :       WASM_MEMORY_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     199             :       kExprI32Const, 0);
     200             : 
     201          12 :   const byte data[] = {11, 22, 33, 44, 55, 66, 77, 88};
     202             :   memcpy(mem, data, sizeof(data));
     203             : 
     204             :   const uint32_t last_5_bytes = kWasmPageSize - 5;
     205             : 
     206             :   // Write all values up to the out-of-bounds access.
     207          12 :   CHECK_EQ(0xDEADBEEF, r.Call(last_5_bytes, 0, 6));
     208          24 :   CheckMemoryEquals(r.builder(), last_5_bytes, {11, 22, 33, 44, 55});
     209             : 
     210             :   // Copy overlapping with destination < source. Copy will happen forwards, up
     211             :   // to the out-of-bounds access.
     212             :   r.builder().BlankMemory();
     213          12 :   memcpy(mem + last_5_bytes, data, 5);
     214          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, last_5_bytes, kWasmPageSize));
     215          24 :   CheckMemoryEquals(r.builder(), 0, {11, 22, 33, 44, 55});
     216             : 
     217             :   // Copy overlapping with source < destination. Copy would happen backwards,
     218             :   // but the first byte to copy is out-of-bounds, so no data should be written.
     219             :   r.builder().BlankMemory();
     220             :   memcpy(mem, data, 5);
     221          12 :   CHECK_EQ(0xDEADBEEF, r.Call(last_5_bytes, 0, kWasmPageSize));
     222          24 :   CheckMemoryEquals(r.builder(), last_5_bytes, {0, 0, 0, 0, 0});
     223          12 : }
     224             : 
     225       26663 : WASM_EXEC_TEST(MemoryCopyOutOfBounds) {
     226             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     227          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     228          12 :   r.builder().AddMemory(kWasmPageSize);
     229          12 :   BUILD(
     230             :       r,
     231             :       WASM_MEMORY_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     232             :       kExprI32Const, 0);
     233             : 
     234             :   // Copy full range is OK.
     235          12 :   CHECK_EQ(0, r.Call(0, 0, kWasmPageSize));
     236             : 
     237             :   // Source range must not be out of bounds.
     238          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, 1, kWasmPageSize));
     239          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, 1000, kWasmPageSize));
     240          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, kWasmPageSize, 1));
     241             : 
     242             :   // Destination range must not be out of bounds.
     243          12 :   CHECK_EQ(0xDEADBEEF, r.Call(1, 0, kWasmPageSize));
     244          12 :   CHECK_EQ(0xDEADBEEF, r.Call(1000, 0, kWasmPageSize));
     245          12 :   CHECK_EQ(0xDEADBEEF, r.Call(kWasmPageSize, 0, 1));
     246             : 
     247             :   // Copy 0 out-of-bounds fails.
     248          12 :   CHECK_EQ(0xDEADBEEF, r.Call(kWasmPageSize + 1, 0, 0));
     249          12 :   CHECK_EQ(0xDEADBEEF, r.Call(0, kWasmPageSize + 1, 0));
     250             : 
     251             :   // Make sure bounds aren't checked with 32-bit wrapping.
     252          12 :   CHECK_EQ(0xDEADBEEF, r.Call(1, 1, 0xFFFFFFFF));
     253          12 : }
     254             : 
     255       26663 : WASM_EXEC_TEST(MemoryFill) {
     256             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     257          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     258          12 :   r.builder().AddMemory(kWasmPageSize);
     259          12 :   BUILD(
     260             :       r,
     261             :       WASM_MEMORY_FILL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     262             :       kExprI32Const, 0);
     263          12 :   CHECK_EQ(0, r.Call(1, 33, 5));
     264          24 :   CheckMemoryEqualsFollowedByZeroes(r.builder(), {0, 33, 33, 33, 33, 33});
     265             : 
     266          12 :   CHECK_EQ(0, r.Call(4, 66, 4));
     267          12 :   CheckMemoryEqualsFollowedByZeroes(r.builder(),
     268          12 :                                     {0, 33, 33, 33, 66, 66, 66, 66});
     269             : 
     270             :   // Fill 0 bytes does nothing.
     271          12 :   CHECK_EQ(0, r.Call(4, 66, 0));
     272          12 :   CheckMemoryEqualsFollowedByZeroes(r.builder(),
     273          12 :                                     {0, 33, 33, 33, 66, 66, 66, 66});
     274             : 
     275             :   // Fill 0 at end of memory region is OK.
     276          12 :   CHECK_EQ(0, r.Call(kWasmPageSize, 66, 0));
     277          12 : }
     278             : 
     279       26663 : WASM_EXEC_TEST(MemoryFillValueWrapsToByte) {
     280             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     281          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     282          12 :   r.builder().AddMemory(kWasmPageSize);
     283          12 :   BUILD(
     284             :       r,
     285             :       WASM_MEMORY_FILL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     286             :       kExprI32Const, 0);
     287          12 :   CHECK_EQ(0, r.Call(0, 1000, 3));
     288             :   const byte expected = 1000 & 255;
     289          12 :   CheckMemoryEqualsFollowedByZeroes(r.builder(),
     290          12 :                                     {expected, expected, expected});
     291          12 : }
     292             : 
     293       26663 : WASM_EXEC_TEST(MemoryFillOutOfBoundsData) {
     294             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     295          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     296          12 :   r.builder().AddMemory(kWasmPageSize);
     297          12 :   BUILD(
     298             :       r,
     299             :       WASM_MEMORY_FILL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     300             :       kExprI32Const, 0);
     301             :   const byte v = 123;
     302          12 :   CHECK_EQ(0xDEADBEEF, r.Call(kWasmPageSize - 5, v, 999));
     303          24 :   CheckMemoryEquals(r.builder(), kWasmPageSize - 6, {0, v, v, v, v, v});
     304          12 : }
     305             : 
     306       26663 : WASM_EXEC_TEST(MemoryFillOutOfBounds) {
     307             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     308          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     309          12 :   r.builder().AddMemory(kWasmPageSize);
     310          12 :   BUILD(
     311             :       r,
     312             :       WASM_MEMORY_FILL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     313             :       kExprI32Const, 0);
     314             : 
     315             :   const byte v = 123;
     316             : 
     317             :   // Destination range must not be out of bounds.
     318          12 :   CHECK_EQ(0xDEADBEEF, r.Call(1, v, kWasmPageSize));
     319          12 :   CHECK_EQ(0xDEADBEEF, r.Call(1000, v, kWasmPageSize));
     320          12 :   CHECK_EQ(0xDEADBEEF, r.Call(kWasmPageSize, v, 1));
     321             : 
     322             :   // Fill 0 out-of-bounds fails.
     323          12 :   CHECK_EQ(0xDEADBEEF, r.Call(kWasmPageSize + 1, v, 0));
     324             : 
     325             :   // Make sure bounds aren't checked with 32-bit wrapping.
     326          12 :   CHECK_EQ(0xDEADBEEF, r.Call(1, v, 0xFFFFFFFF));
     327          12 : }
     328             : 
     329       26663 : WASM_EXEC_TEST(DataDropTwice) {
     330             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     331          24 :   WasmRunner<uint32_t> r(execution_tier);
     332          12 :   r.builder().AddMemory(kWasmPageSize);
     333          12 :   const byte data[] = {0};
     334          12 :   r.builder().AddPassiveDataSegment(Vector<const byte>(data));
     335          12 :   BUILD(r, WASM_DATA_DROP(0), kExprI32Const, 0);
     336             : 
     337          12 :   CHECK_EQ(0, r.Call());
     338          12 :   CHECK_EQ(0xDEADBEEF, r.Call());
     339          12 : }
     340             : 
     341       26663 : WASM_EXEC_TEST(DataDropThenMemoryInit) {
     342             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     343          24 :   WasmRunner<uint32_t> r(execution_tier);
     344          12 :   r.builder().AddMemory(kWasmPageSize);
     345          12 :   const byte data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
     346          12 :   r.builder().AddPassiveDataSegment(Vector<const byte>(data));
     347          12 :   BUILD(r, WASM_DATA_DROP(0),
     348             :         WASM_MEMORY_INIT(0, WASM_I32V_1(0), WASM_I32V_1(1), WASM_I32V_1(2)),
     349             :         kExprI32Const, 0);
     350             : 
     351          12 :   CHECK_EQ(0xDEADBEEF, r.Call());
     352          12 : }
     353             : 
     354       26663 : WASM_EXEC_TEST(TableCopyInbounds) {
     355             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     356          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     357             :   const uint32_t kTableSize = 5;
     358          12 :   r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
     359          12 :   BUILD(
     360             :       r,
     361             :       WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     362             :       kExprI32Const, 0);
     363             : 
     364         156 :   for (uint32_t i = 0; i <= kTableSize; ++i) {
     365          72 :     r.CheckCallViaJS(0, 0, 0, i);  // nop
     366          72 :     r.CheckCallViaJS(0, 0, i, kTableSize - i);
     367          72 :     r.CheckCallViaJS(0, i, 0, kTableSize - i);
     368             :   }
     369          12 : }
     370             : 
     371             : namespace {
     372             : template <typename... Args>
     373         120 : void CheckTable(Isolate* isolate, Handle<WasmTableObject> table, Args... args) {
     374             :   uint32_t args_length = static_cast<uint32_t>(sizeof...(args));
     375         120 :   CHECK_EQ(table->current_length(), args_length);
     376         120 :   Handle<Object> handles[] = {args...};
     377        1320 :   for (uint32_t i = 0; i < args_length; ++i) {
     378        1200 :     CHECK(WasmTableObject::Get(isolate, table, i).is_identical_to(handles[i]));
     379             :   }
     380         120 : }
     381             : 
     382             : template <typename WasmRunner, typename... Args>
     383         180 : void CheckTableCall(Isolate* isolate, Handle<WasmTableObject> table,
     384             :                     WasmRunner& r, uint32_t function_index, Args... args) {
     385             :   uint32_t args_length = static_cast<uint32_t>(sizeof...(args));
     386         180 :   CHECK_EQ(table->current_length(), args_length);
     387         180 :   double expected[] = {args...};
     388        1980 :   for (uint32_t i = 0; i < args_length; ++i) {
     389         900 :     Handle<Object> buffer[] = {isolate->factory()->NewNumber(i)};
     390         900 :     r.CheckCallApplyViaJS(expected[i], function_index, buffer, 1);
     391             :   }
     392         180 : }
     393             : }  // namespace
     394             : 
     395       26663 : WASM_EXEC_TEST(TableInitElems) {
     396             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     397             :   Isolate* isolate = CcTest::InitIsolateOnce();
     398             :   HandleScope scope(isolate);
     399          12 :   TestSignatures sigs;
     400          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     401             :   const uint32_t kTableSize = 5;
     402             :   std::vector<uint32_t> function_indexes;
     403          12 :   const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
     404             : 
     405         132 :   for (uint32_t i = 0; i < kTableSize; ++i) {
     406          60 :     WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
     407          60 :     BUILD(fn, WASM_I32V_1(i));
     408             :     fn.SetSigIndex(sig_index);
     409         120 :     function_indexes.push_back(fn.function_index());
     410             :   }
     411             : 
     412             :   // Passive element segment has [f0, f1, f2, f3, f4, null].
     413          12 :   function_indexes.push_back(WasmElemSegment::kNullIndex);
     414             : 
     415          12 :   r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
     416          12 :   r.builder().AddPassiveElementSegment(function_indexes);
     417             : 
     418          12 :   WasmFunctionCompiler& call = r.NewFunction(sigs.i_i(), "call");
     419          12 :   BUILD(call, WASM_CALL_INDIRECT0(sig_index, WASM_GET_LOCAL(0)));
     420             :   const uint32_t call_index = call.function_index();
     421             : 
     422          12 :   BUILD(r,
     423             :         WASM_TABLE_INIT(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
     424             :                         WASM_GET_LOCAL(2)),
     425             :         kExprI32Const, 0);
     426             : 
     427             :   auto table = handle(
     428             :       WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
     429          12 :       isolate);
     430             :   const double null = 0xDEADBEEF;
     431             : 
     432          12 :   CheckTableCall(isolate, table, r, call_index, null, null, null, null, null);
     433             : 
     434             :   // 0 count is ok in bounds, and at end of regions.
     435          12 :   r.CheckCallViaJS(0, 0, 0, 0);
     436          12 :   r.CheckCallViaJS(0, kTableSize, 0, 0);
     437          12 :   r.CheckCallViaJS(0, 0, kTableSize, 0);
     438             : 
     439             :   // Test actual writes.
     440          12 :   r.CheckCallViaJS(0, 0, 0, 1);
     441          12 :   CheckTableCall(isolate, table, r, call_index, 0, null, null, null, null);
     442          12 :   r.CheckCallViaJS(0, 0, 0, 2);
     443          12 :   CheckTableCall(isolate, table, r, call_index, 0, 1, null, null, null);
     444          12 :   r.CheckCallViaJS(0, 0, 0, 3);
     445          12 :   CheckTableCall(isolate, table, r, call_index, 0, 1, 2, null, null);
     446          12 :   r.CheckCallViaJS(0, 3, 0, 2);
     447          12 :   CheckTableCall(isolate, table, r, call_index, 0, 1, 2, 0, 1);
     448          12 :   r.CheckCallViaJS(0, 3, 1, 2);
     449          12 :   CheckTableCall(isolate, table, r, call_index, 0, 1, 2, 1, 2);
     450          12 :   r.CheckCallViaJS(0, 3, 2, 2);
     451          12 :   CheckTableCall(isolate, table, r, call_index, 0, 1, 2, 2, 3);
     452          12 :   r.CheckCallViaJS(0, 3, 3, 2);
     453          12 :   CheckTableCall(isolate, table, r, call_index, 0, 1, 2, 3, 4);
     454          12 : }
     455             : 
     456       26663 : WASM_EXEC_TEST(TableInitOob) {
     457             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     458             :   Isolate* isolate = CcTest::InitIsolateOnce();
     459             :   HandleScope scope(isolate);
     460          12 :   TestSignatures sigs;
     461          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     462             :   const uint32_t kTableSize = 5;
     463             :   std::vector<uint32_t> function_indexes;
     464          12 :   const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
     465             : 
     466         132 :   for (uint32_t i = 0; i < kTableSize; ++i) {
     467          60 :     WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
     468          60 :     BUILD(fn, WASM_I32V_1(i));
     469             :     fn.SetSigIndex(sig_index);
     470         120 :     function_indexes.push_back(fn.function_index());
     471             :   }
     472             : 
     473          12 :   r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
     474          12 :   r.builder().AddPassiveElementSegment(function_indexes);
     475             : 
     476          12 :   WasmFunctionCompiler& call = r.NewFunction(sigs.i_i(), "call");
     477          12 :   BUILD(call, WASM_CALL_INDIRECT0(sig_index, WASM_GET_LOCAL(0)));
     478             :   const uint32_t call_index = call.function_index();
     479             : 
     480          12 :   BUILD(r,
     481             :         WASM_TABLE_INIT(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1),
     482             :                         WASM_GET_LOCAL(2)),
     483             :         kExprI32Const, 0);
     484             : 
     485             :   auto table = handle(
     486             :       WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
     487          12 :       isolate);
     488             :   const double null = 0xDEADBEEF;
     489             : 
     490          12 :   CheckTableCall(isolate, table, r, call_index, null, null, null, null, null);
     491             : 
     492             :   // Write all values up to the out-of-bounds write.
     493          12 :   r.CheckCallViaJS(0xDEADBEEF, 3, 0, 3);
     494          12 :   CheckTableCall(isolate, table, r, call_index, null, null, null, 0, 1);
     495             : 
     496             :   // Write all values up to the out-of-bounds read.
     497          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 3, 3);
     498          12 :   CheckTableCall(isolate, table, r, call_index, 3, 4, null, 0, 1);
     499             : 
     500             :   // 0-count is oob.
     501          12 :   r.CheckCallViaJS(0xDEADBEEF, kTableSize + 1, 0, 0);
     502          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, kTableSize + 1, 0);
     503             : 
     504          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 0, 6);
     505          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 1, 5);
     506          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 2, 4);
     507          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 3, 3);
     508          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 4, 2);
     509          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 5, 1);
     510             : 
     511          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 0, 6);
     512          12 :   r.CheckCallViaJS(0xDEADBEEF, 1, 0, 5);
     513          12 :   r.CheckCallViaJS(0xDEADBEEF, 2, 0, 4);
     514          12 :   r.CheckCallViaJS(0xDEADBEEF, 3, 0, 3);
     515          12 :   r.CheckCallViaJS(0xDEADBEEF, 4, 0, 2);
     516          12 :   r.CheckCallViaJS(0xDEADBEEF, 5, 0, 1);
     517             : 
     518          12 :   r.CheckCallViaJS(0xDEADBEEF, 10, 0, 1);
     519          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 10, 1);
     520          12 : }
     521             : 
     522       26663 : WASM_EXEC_TEST(TableCopyElems) {
     523             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     524             :   Isolate* isolate = CcTest::InitIsolateOnce();
     525             :   HandleScope scope(isolate);
     526          12 :   TestSignatures sigs;
     527          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     528             :   const uint32_t kTableSize = 5;
     529             :   uint16_t function_indexes[kTableSize];
     530          12 :   const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
     531             : 
     532         132 :   for (uint32_t i = 0; i < kTableSize; ++i) {
     533          60 :     WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
     534          60 :     BUILD(fn, WASM_I32V_1(i));
     535             :     fn.SetSigIndex(sig_index);
     536          60 :     function_indexes[i] = fn.function_index();
     537             :   }
     538             : 
     539          12 :   r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
     540             : 
     541          12 :   BUILD(
     542             :       r,
     543             :       WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     544             :       kExprI32Const, 0);
     545             : 
     546             :   auto table = handle(
     547             :       WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
     548          12 :       isolate);
     549          12 :   auto f0 = WasmTableObject::Get(isolate, table, 0);
     550          12 :   auto f1 = WasmTableObject::Get(isolate, table, 1);
     551          12 :   auto f2 = WasmTableObject::Get(isolate, table, 2);
     552          12 :   auto f3 = WasmTableObject::Get(isolate, table, 3);
     553          12 :   auto f4 = WasmTableObject::Get(isolate, table, 4);
     554             : 
     555          12 :   CheckTable(isolate, table, f0, f1, f2, f3, f4);
     556          12 :   r.CheckCallViaJS(0, 0, 1, 1);
     557          12 :   CheckTable(isolate, table, f1, f1, f2, f3, f4);
     558          12 :   r.CheckCallViaJS(0, 0, 1, 2);
     559          12 :   CheckTable(isolate, table, f1, f2, f2, f3, f4);
     560          12 :   r.CheckCallViaJS(0, 3, 0, 2);
     561          12 :   CheckTable(isolate, table, f1, f2, f2, f1, f2);
     562          12 :   r.CheckCallViaJS(0, 1, 0, 2);
     563          12 :   CheckTable(isolate, table, f1, f1, f2, f1, f2);
     564          12 : }
     565             : 
     566       26663 : WASM_EXEC_TEST(TableCopyCalls) {
     567             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     568             :   Isolate* isolate = CcTest::InitIsolateOnce();
     569             :   HandleScope scope(isolate);
     570          12 :   TestSignatures sigs;
     571          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     572             :   const uint32_t kTableSize = 5;
     573             :   uint16_t function_indexes[kTableSize];
     574          12 :   const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
     575             : 
     576         132 :   for (uint32_t i = 0; i < kTableSize; ++i) {
     577          60 :     WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
     578          60 :     BUILD(fn, WASM_I32V_1(i));
     579             :     fn.SetSigIndex(sig_index);
     580          60 :     function_indexes[i] = fn.function_index();
     581             :   }
     582             : 
     583          12 :   r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
     584             : 
     585          12 :   WasmFunctionCompiler& call = r.NewFunction(sigs.i_i(), "call");
     586          12 :   BUILD(call, WASM_CALL_INDIRECT0(sig_index, WASM_GET_LOCAL(0)));
     587             :   const uint32_t call_index = call.function_index();
     588             : 
     589          12 :   BUILD(
     590             :       r,
     591             :       WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     592             :       kExprI32Const, 0);
     593             : 
     594             :   auto table = handle(
     595             :       WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
     596          12 :       isolate);
     597             : 
     598          12 :   CheckTableCall(isolate, table, r, call_index, 0, 1, 2, 3, 4);
     599          12 :   r.CheckCallViaJS(0, 0, 1, 1);
     600          12 :   CheckTableCall(isolate, table, r, call_index, 1, 1, 2, 3, 4);
     601          12 :   r.CheckCallViaJS(0, 0, 1, 2);
     602          12 :   CheckTableCall(isolate, table, r, call_index, 1, 2, 2, 3, 4);
     603          12 :   r.CheckCallViaJS(0, 3, 0, 2);
     604          12 :   CheckTableCall(isolate, table, r, call_index, 1, 2, 2, 1, 2);
     605          12 : }
     606             : 
     607       26663 : WASM_EXEC_TEST(TableCopyOobWrites) {
     608             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     609             :   Isolate* isolate = CcTest::InitIsolateOnce();
     610             :   HandleScope scope(isolate);
     611          12 :   TestSignatures sigs;
     612          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     613             :   const uint32_t kTableSize = 5;
     614             :   uint16_t function_indexes[kTableSize];
     615          12 :   const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
     616             : 
     617         132 :   for (uint32_t i = 0; i < kTableSize; ++i) {
     618          60 :     WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
     619          60 :     BUILD(fn, WASM_I32V_1(i));
     620             :     fn.SetSigIndex(sig_index);
     621          60 :     function_indexes[i] = fn.function_index();
     622             :   }
     623             : 
     624          12 :   r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
     625             : 
     626          12 :   BUILD(
     627             :       r,
     628             :       WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     629             :       kExprI32Const, 0);
     630             : 
     631             :   auto table = handle(
     632             :       WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
     633          12 :       isolate);
     634          12 :   auto f0 = WasmTableObject::Get(isolate, table, 0);
     635          12 :   auto f1 = WasmTableObject::Get(isolate, table, 1);
     636          12 :   auto f2 = WasmTableObject::Get(isolate, table, 2);
     637          12 :   auto f3 = WasmTableObject::Get(isolate, table, 3);
     638          12 :   auto f4 = WasmTableObject::Get(isolate, table, 4);
     639             : 
     640          12 :   CheckTable(isolate, table, f0, f1, f2, f3, f4);
     641             : 
     642             :   // Non-overlapping, src < dst.
     643          12 :   r.CheckCallViaJS(0xDEADBEEF, 3, 0, 3);
     644          12 :   CheckTable(isolate, table, f0, f1, f2, f0, f1);
     645             : 
     646             :   // Non-overlapping, dst < src.
     647          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 4, 2);
     648          12 :   CheckTable(isolate, table, f1, f1, f2, f0, f1);
     649             : 
     650             :   // Overlapping, src < dst. This is required to copy backward, but the first
     651             :   // access will be out-of-bounds, so nothing changes.
     652          12 :   r.CheckCallViaJS(0xDEADBEEF, 3, 0, 99);
     653          12 :   CheckTable(isolate, table, f1, f1, f2, f0, f1);
     654             : 
     655             :   // Overlapping, dst < src.
     656          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 1, 99);
     657          12 :   CheckTable(isolate, table, f1, f2, f0, f1, f1);
     658          12 : }
     659             : 
     660       26663 : WASM_EXEC_TEST(TableCopyOob1) {
     661             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     662          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     663             :   const uint32_t kTableSize = 5;
     664             : 
     665          12 :   r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
     666             : 
     667          12 :   BUILD(
     668             :       r,
     669             :       WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     670             :       kExprI32Const, 0);
     671             : 
     672          12 :   r.CheckCallViaJS(0, 0, 0, 1);           // nop
     673          12 :   r.CheckCallViaJS(0, 0, 0, kTableSize);  // nop
     674          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 0, kTableSize + 1);
     675          12 :   r.CheckCallViaJS(0xDEADBEEF, 1, 0, kTableSize);
     676          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 1, kTableSize);
     677             : 
     678             :   {
     679             :     const uint32_t big = 1000000;
     680          12 :     r.CheckCallViaJS(0xDEADBEEF, big, 0, 0);
     681          12 :     r.CheckCallViaJS(0xDEADBEEF, 0, big, 0);
     682             :   }
     683             : 
     684         564 :   for (uint32_t big = 4294967295; big > 1000; big >>= 1) {
     685         276 :     r.CheckCallViaJS(0xDEADBEEF, big, 0, 1);
     686         276 :     r.CheckCallViaJS(0xDEADBEEF, 0, big, 1);
     687         276 :     r.CheckCallViaJS(0xDEADBEEF, 0, 0, big);
     688             :   }
     689             : 
     690         708 :   for (uint32_t big = -1000; big != 0; big <<= 1) {
     691         348 :     r.CheckCallViaJS(0xDEADBEEF, big, 0, 1);
     692         348 :     r.CheckCallViaJS(0xDEADBEEF, 0, big, 1);
     693         348 :     r.CheckCallViaJS(0xDEADBEEF, 0, 0, big);
     694             :   }
     695          12 : }
     696             : 
     697       26663 : WASM_EXEC_TEST(ElemDropTwice) {
     698             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     699          24 :   WasmRunner<uint32_t> r(execution_tier);
     700          12 :   r.builder().AddIndirectFunctionTable(nullptr, 1);
     701          24 :   r.builder().AddPassiveElementSegment({});
     702          12 :   BUILD(r, WASM_ELEM_DROP(0), kExprI32Const, 0);
     703             : 
     704          12 :   r.CheckCallViaJS(0);
     705          12 :   r.CheckCallViaJS(0xDEADBEEF);
     706          12 : }
     707             : 
     708       26663 : WASM_EXEC_TEST(ElemDropThenTableInit) {
     709             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     710          24 :   WasmRunner<uint32_t> r(execution_tier);
     711          12 :   r.builder().AddIndirectFunctionTable(nullptr, 1);
     712          24 :   r.builder().AddPassiveElementSegment({});
     713          12 :   BUILD(r, WASM_ELEM_DROP(0),
     714             :         WASM_TABLE_INIT(0, WASM_I32V_1(0), WASM_I32V_1(0), WASM_I32V_1(0)),
     715             :         kExprI32Const, 0);
     716             : 
     717          12 :   r.CheckCallViaJS(0xDEADBEEF);
     718          12 : }
     719             : 
     720             : }  // namespace test_run_wasm_bulk_memory
     721             : }  // namespace wasm
     722             : }  // namespace internal
     723       79917 : }  // namespace v8

Generated by: LCOV version 1.10