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: 290 290 100.0 %
Date: 2019-03-21 Functions: 79 79 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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       26087 : 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          48 : 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          48 :   CHECK_EQ(table->current_length(), args_length);
     387          48 :   double expected[] = {args...};
     388         528 :   for (uint32_t i = 0; i < args_length; ++i) {
     389         240 :     Handle<Object> buffer[] = {isolate->factory()->NewNumber(i)};
     390         240 :     r.CheckCallApplyViaJS(expected[i], function_index, buffer, 1);
     391             :   }
     392          48 : }
     393             : }  // namespace
     394             : 
     395       26087 : WASM_EXEC_TEST(TableCopyElems) {
     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             :   uint16_t function_indexes[kTableSize];
     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          60 :     function_indexes[i] = fn.function_index();
     410             :   }
     411             : 
     412          12 :   r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
     413             : 
     414          12 :   BUILD(
     415             :       r,
     416             :       WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     417             :       kExprI32Const, 0);
     418             : 
     419             :   auto table = handle(
     420             :       WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
     421          12 :       isolate);
     422          12 :   auto f0 = WasmTableObject::Get(isolate, table, 0);
     423          12 :   auto f1 = WasmTableObject::Get(isolate, table, 1);
     424          12 :   auto f2 = WasmTableObject::Get(isolate, table, 2);
     425          12 :   auto f3 = WasmTableObject::Get(isolate, table, 3);
     426          12 :   auto f4 = WasmTableObject::Get(isolate, table, 4);
     427             : 
     428          12 :   CheckTable(isolate, table, f0, f1, f2, f3, f4);
     429          12 :   r.CheckCallViaJS(0, 0, 1, 1);
     430          12 :   CheckTable(isolate, table, f1, f1, f2, f3, f4);
     431          12 :   r.CheckCallViaJS(0, 0, 1, 2);
     432          12 :   CheckTable(isolate, table, f1, f2, f2, f3, f4);
     433          12 :   r.CheckCallViaJS(0, 3, 0, 2);
     434          12 :   CheckTable(isolate, table, f1, f2, f2, f1, f2);
     435          12 :   r.CheckCallViaJS(0, 1, 0, 2);
     436          12 :   CheckTable(isolate, table, f1, f1, f2, f1, f2);
     437          12 : }
     438             : 
     439       26087 : WASM_EXEC_TEST(TableCopyCalls) {
     440             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     441             :   Isolate* isolate = CcTest::InitIsolateOnce();
     442             :   HandleScope scope(isolate);
     443          12 :   TestSignatures sigs;
     444          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     445             :   const uint32_t kTableSize = 5;
     446             :   uint16_t function_indexes[kTableSize];
     447          12 :   const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
     448             : 
     449         132 :   for (uint32_t i = 0; i < kTableSize; ++i) {
     450          60 :     WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
     451          60 :     BUILD(fn, WASM_I32V_1(i));
     452             :     fn.SetSigIndex(sig_index);
     453          60 :     function_indexes[i] = fn.function_index();
     454             :   }
     455             : 
     456          12 :   r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
     457             : 
     458          12 :   WasmFunctionCompiler& call = r.NewFunction(sigs.i_i(), "call");
     459          12 :   BUILD(call, WASM_CALL_INDIRECT0(sig_index, WASM_GET_LOCAL(0)));
     460             :   const uint32_t call_index = call.function_index();
     461             : 
     462          12 :   BUILD(
     463             :       r,
     464             :       WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     465             :       kExprI32Const, 0);
     466             : 
     467             :   auto table = handle(
     468             :       WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
     469          12 :       isolate);
     470             : 
     471          12 :   CheckTableCall(isolate, table, r, call_index, 0, 1, 2, 3, 4);
     472          12 :   r.CheckCallViaJS(0, 0, 1, 1);
     473          12 :   CheckTableCall(isolate, table, r, call_index, 1, 1, 2, 3, 4);
     474          12 :   r.CheckCallViaJS(0, 0, 1, 2);
     475          12 :   CheckTableCall(isolate, table, r, call_index, 1, 2, 2, 3, 4);
     476          12 :   r.CheckCallViaJS(0, 3, 0, 2);
     477          12 :   CheckTableCall(isolate, table, r, call_index, 1, 2, 2, 1, 2);
     478          12 : }
     479             : 
     480       26087 : WASM_EXEC_TEST(TableCopyOobWrites) {
     481             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     482             :   Isolate* isolate = CcTest::InitIsolateOnce();
     483             :   HandleScope scope(isolate);
     484          12 :   TestSignatures sigs;
     485          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     486             :   const uint32_t kTableSize = 5;
     487             :   uint16_t function_indexes[kTableSize];
     488          12 :   const uint32_t sig_index = r.builder().AddSignature(sigs.i_v());
     489             : 
     490         132 :   for (uint32_t i = 0; i < kTableSize; ++i) {
     491          60 :     WasmFunctionCompiler& fn = r.NewFunction(sigs.i_v(), "f");
     492          60 :     BUILD(fn, WASM_I32V_1(i));
     493             :     fn.SetSigIndex(sig_index);
     494          60 :     function_indexes[i] = fn.function_index();
     495             :   }
     496             : 
     497          12 :   r.builder().AddIndirectFunctionTable(function_indexes, kTableSize);
     498             : 
     499          12 :   BUILD(
     500             :       r,
     501             :       WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     502             :       kExprI32Const, 0);
     503             : 
     504             :   auto table = handle(
     505             :       WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
     506          12 :       isolate);
     507          12 :   auto f0 = WasmTableObject::Get(isolate, table, 0);
     508          12 :   auto f1 = WasmTableObject::Get(isolate, table, 1);
     509          12 :   auto f2 = WasmTableObject::Get(isolate, table, 2);
     510          12 :   auto f3 = WasmTableObject::Get(isolate, table, 3);
     511          12 :   auto f4 = WasmTableObject::Get(isolate, table, 4);
     512             : 
     513          12 :   CheckTable(isolate, table, f0, f1, f2, f3, f4);
     514             : 
     515             :   // Non-overlapping, src < dst.
     516          12 :   r.CheckCallViaJS(0xDEADBEEF, 3, 0, 3);
     517          12 :   CheckTable(isolate, table, f0, f1, f2, f0, f1);
     518             : 
     519             :   // Non-overlapping, dst < src.
     520          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 4, 2);
     521          12 :   CheckTable(isolate, table, f1, f1, f2, f0, f1);
     522             : 
     523             :   // Overlapping, src < dst. This is required to copy backward, but the first
     524             :   // access will be out-of-bounds, so nothing changes.
     525          12 :   r.CheckCallViaJS(0xDEADBEEF, 3, 0, 99);
     526          12 :   CheckTable(isolate, table, f1, f1, f2, f0, f1);
     527             : 
     528             :   // Overlapping, dst < src.
     529          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 1, 99);
     530          12 :   CheckTable(isolate, table, f1, f2, f0, f1, f1);
     531          12 : }
     532             : 
     533       26087 : WASM_EXEC_TEST(TableCopyOob1) {
     534             :   EXPERIMENTAL_FLAG_SCOPE(bulk_memory);
     535          24 :   WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier);
     536             :   const uint32_t kTableSize = 5;
     537             : 
     538          12 :   r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
     539             : 
     540          12 :   BUILD(
     541             :       r,
     542             :       WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
     543             :       kExprI32Const, 0);
     544             : 
     545          12 :   r.CheckCallViaJS(0, 0, 0, 1);           // nop
     546          12 :   r.CheckCallViaJS(0, 0, 0, kTableSize);  // nop
     547          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 0, kTableSize + 1);
     548          12 :   r.CheckCallViaJS(0xDEADBEEF, 1, 0, kTableSize);
     549          12 :   r.CheckCallViaJS(0xDEADBEEF, 0, 1, kTableSize);
     550             : 
     551             :   {
     552             :     const uint32_t big = 1000000;
     553          12 :     r.CheckCallViaJS(0xDEADBEEF, big, 0, 0);
     554          12 :     r.CheckCallViaJS(0xDEADBEEF, 0, big, 0);
     555             :   }
     556             : 
     557         564 :   for (uint32_t big = 4294967295; big > 1000; big >>= 1) {
     558         276 :     r.CheckCallViaJS(0xDEADBEEF, big, 0, 1);
     559         276 :     r.CheckCallViaJS(0xDEADBEEF, 0, big, 1);
     560         276 :     r.CheckCallViaJS(0xDEADBEEF, 0, 0, big);
     561             :   }
     562             : 
     563         708 :   for (uint32_t big = -1000; big != 0; big <<= 1) {
     564         348 :     r.CheckCallViaJS(0xDEADBEEF, big, 0, 1);
     565         348 :     r.CheckCallViaJS(0xDEADBEEF, 0, big, 1);
     566         348 :     r.CheckCallViaJS(0xDEADBEEF, 0, 0, big);
     567             :   }
     568          12 : }
     569             : 
     570             : }  // namespace test_run_wasm_bulk_memory
     571             : }  // namespace wasm
     572             : }  // namespace internal
     573       78189 : }  // namespace v8

Generated by: LCOV version 1.10