LCOV - code coverage report
Current view: top level - test/cctest/wasm - test-run-wasm-module.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 441 445 99.1 %
Date: 2019-01-20 Functions: 40 42 95.2 %

          Line data    Source code
       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
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <stdlib.h>
       6             : #include <string.h>
       7             : 
       8             : #include "src/api-inl.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/snapshot/code-serializer.h"
      11             : #include "src/version.h"
      12             : #include "src/wasm/module-decoder.h"
      13             : #include "src/wasm/wasm-engine.h"
      14             : #include "src/wasm/wasm-memory.h"
      15             : #include "src/wasm/wasm-module-builder.h"
      16             : #include "src/wasm/wasm-module.h"
      17             : #include "src/wasm/wasm-objects-inl.h"
      18             : #include "src/wasm/wasm-opcodes.h"
      19             : 
      20             : #include "test/cctest/cctest.h"
      21             : #include "test/common/wasm/flag-utils.h"
      22             : #include "test/common/wasm/test-signatures.h"
      23             : #include "test/common/wasm/wasm-macro-gen.h"
      24             : #include "test/common/wasm/wasm-module-runner.h"
      25             : 
      26             : namespace v8 {
      27             : namespace internal {
      28             : namespace wasm {
      29             : namespace test_run_wasm_module {
      30             : 
      31             : using testing::CompileAndInstantiateForTesting;
      32             : 
      33             : namespace {
      34             : void Cleanup(Isolate* isolate = CcTest::InitIsolateOnce()) {
      35             :   // By sending a low memory notifications, we will try hard to collect all
      36             :   // garbage and will therefore also invoke all weak callbacks of actually
      37             :   // unreachable persistent handles.
      38         145 :   reinterpret_cast<v8::Isolate*>(isolate)->LowMemoryNotification();
      39             : }
      40             : 
      41         205 : void TestModule(Zone* zone, WasmModuleBuilder* builder,
      42             :                 int32_t expected_result) {
      43             :   ZoneBuffer buffer(zone);
      44         205 :   builder->WriteTo(buffer);
      45             : 
      46         205 :   Isolate* isolate = CcTest::InitIsolateOnce();
      47             :   HandleScope scope(isolate);
      48         205 :   testing::SetupIsolateForWasmModule(isolate);
      49             :   int32_t result =
      50         205 :       testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
      51         205 :   CHECK_EQ(expected_result, result);
      52         205 : }
      53             : 
      54           5 : void TestModuleException(Zone* zone, WasmModuleBuilder* builder) {
      55             :   ZoneBuffer buffer(zone);
      56           5 :   builder->WriteTo(buffer);
      57             : 
      58           5 :   Isolate* isolate = CcTest::InitIsolateOnce();
      59             :   HandleScope scope(isolate);
      60           5 :   testing::SetupIsolateForWasmModule(isolate);
      61          10 :   v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
      62           5 :   testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
      63           5 :   CHECK(try_catch.HasCaught());
      64           5 :   isolate->clear_pending_exception();
      65           5 : }
      66             : 
      67         235 : void ExportAsMain(WasmFunctionBuilder* f) {
      68         235 :   f->builder()->AddExport(CStrVector("main"), f);
      69         235 : }
      70             : 
      71             : #define EMIT_CODE_WITH_END(f, code)  \
      72             :   do {                               \
      73             :     f->EmitCode(code, sizeof(code)); \
      74             :     f->Emit(kExprEnd);               \
      75             :   } while (false)
      76             : 
      77             : }  // namespace
      78             : 
      79       28342 : TEST(Run_WasmModule_Return114) {
      80             :   {
      81             :     static const int32_t kReturnValue = 114;
      82           5 :     TestSignatures sigs;
      83           5 :     v8::internal::AccountingAllocator allocator;
      84          10 :     Zone zone(&allocator, ZONE_NAME);
      85             : 
      86           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
      87           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
      88           5 :     ExportAsMain(f);
      89           5 :     byte code[] = {WASM_I32V_2(kReturnValue)};
      90           5 :     EMIT_CODE_WITH_END(f, code);
      91          10 :     TestModule(&zone, builder, kReturnValue);
      92             :   }
      93           5 :   Cleanup();
      94           5 : }
      95             : 
      96       28342 : TEST(Run_WasmModule_CallAdd) {
      97             :   {
      98           5 :     v8::internal::AccountingAllocator allocator;
      99          10 :     Zone zone(&allocator, ZONE_NAME);
     100           5 :     TestSignatures sigs;
     101             : 
     102           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     103             : 
     104          10 :     WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_ii());
     105             :     uint16_t param1 = 0;
     106             :     uint16_t param2 = 1;
     107             :     byte code1[] = {
     108           5 :         WASM_I32_ADD(WASM_GET_LOCAL(param1), WASM_GET_LOCAL(param2))};
     109           5 :     EMIT_CODE_WITH_END(f1, code1);
     110             : 
     111           5 :     WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v());
     112             : 
     113           5 :     ExportAsMain(f2);
     114             :     byte code2[] = {
     115          10 :         WASM_CALL_FUNCTION(f1->func_index(), WASM_I32V_2(77), WASM_I32V_1(22))};
     116           5 :     EMIT_CODE_WITH_END(f2, code2);
     117          10 :     TestModule(&zone, builder, 99);
     118             :   }
     119           5 :   Cleanup();
     120           5 : }
     121             : 
     122       28342 : TEST(Run_WasmModule_ReadLoadedDataSegment) {
     123             :   {
     124             :     static const byte kDataSegmentDest0 = 12;
     125           5 :     v8::internal::AccountingAllocator allocator;
     126          10 :     Zone zone(&allocator, ZONE_NAME);
     127           5 :     TestSignatures sigs;
     128             : 
     129           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     130           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     131             : 
     132           5 :     ExportAsMain(f);
     133             :     byte code[] = {
     134           5 :         WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V_1(kDataSegmentDest0))};
     135           5 :     EMIT_CODE_WITH_END(f, code);
     136           5 :     byte data[] = {0xAA, 0xBB, 0xCC, 0xDD};
     137           5 :     builder->AddDataSegment(data, sizeof(data), kDataSegmentDest0);
     138          10 :     TestModule(&zone, builder, 0xDDCCBBAA);
     139             :   }
     140           5 :   Cleanup();
     141           5 : }
     142             : 
     143       28342 : TEST(Run_WasmModule_CheckMemoryIsZero) {
     144             :   {
     145             :     static const int kCheckSize = 16 * 1024;
     146           5 :     v8::internal::AccountingAllocator allocator;
     147          10 :     Zone zone(&allocator, ZONE_NAME);
     148           5 :     TestSignatures sigs;
     149             : 
     150           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     151           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     152             : 
     153           5 :     uint16_t localIndex = f->AddLocal(kWasmI32);
     154           5 :     ExportAsMain(f);
     155           5 :     byte code[] = {WASM_BLOCK_I(
     156             :         WASM_WHILE(
     157             :             WASM_I32_LTS(WASM_GET_LOCAL(localIndex), WASM_I32V_3(kCheckSize)),
     158             :             WASM_IF_ELSE(
     159             :                 WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(localIndex)),
     160             :                 WASM_BRV(3, WASM_I32V_1(-1)),
     161             :                 WASM_INC_LOCAL_BY(localIndex, 4))),
     162          10 :         WASM_I32V_1(11))};
     163           5 :     EMIT_CODE_WITH_END(f, code);
     164          10 :     TestModule(&zone, builder, 11);
     165             :   }
     166           5 :   Cleanup();
     167           5 : }
     168             : 
     169       28342 : TEST(Run_WasmModule_CallMain_recursive) {
     170             :   {
     171           5 :     v8::internal::AccountingAllocator allocator;
     172          10 :     Zone zone(&allocator, ZONE_NAME);
     173           5 :     TestSignatures sigs;
     174             : 
     175           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     176           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     177             : 
     178           5 :     uint16_t localIndex = f->AddLocal(kWasmI32);
     179           5 :     ExportAsMain(f);
     180             :     byte code[] = {
     181           5 :         WASM_SET_LOCAL(localIndex,
     182             :                        WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO)),
     183           5 :         WASM_IF_ELSE_I(WASM_I32_LTS(WASM_GET_LOCAL(localIndex), WASM_I32V_1(5)),
     184             :                        WASM_SEQ(WASM_STORE_MEM(MachineType::Int32(), WASM_ZERO,
     185             :                                                WASM_INC_LOCAL(localIndex)),
     186             :                                 WASM_CALL_FUNCTION0(0)),
     187          15 :                        WASM_I32V_1(55))};
     188           5 :     EMIT_CODE_WITH_END(f, code);
     189          10 :     TestModule(&zone, builder, 55);
     190             :   }
     191           5 :   Cleanup();
     192           5 : }
     193             : 
     194       28342 : TEST(Run_WasmModule_Global) {
     195             :   {
     196           5 :     v8::internal::AccountingAllocator allocator;
     197          10 :     Zone zone(&allocator, ZONE_NAME);
     198           5 :     TestSignatures sigs;
     199             : 
     200           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     201           5 :     uint32_t global1 = builder->AddGlobal(kWasmI32, false);
     202           5 :     uint32_t global2 = builder->AddGlobal(kWasmI32, false);
     203          10 :     WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_v());
     204             :     byte code1[] = {
     205           5 :         WASM_I32_ADD(WASM_GET_GLOBAL(global1), WASM_GET_GLOBAL(global2))};
     206           5 :     EMIT_CODE_WITH_END(f1, code1);
     207           5 :     WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v());
     208           5 :     ExportAsMain(f2);
     209             :     byte code2[] = {WASM_SET_GLOBAL(global1, WASM_I32V_1(56)),
     210             :                     WASM_SET_GLOBAL(global2, WASM_I32V_1(41)),
     211          10 :                     WASM_RETURN1(WASM_CALL_FUNCTION0(f1->func_index()))};
     212           5 :     EMIT_CODE_WITH_END(f2, code2);
     213          10 :     TestModule(&zone, builder, 97);
     214             :   }
     215           5 :   Cleanup();
     216           5 : }
     217             : 
     218       28342 : TEST(MemorySize) {
     219             :   {
     220             :     // Initial memory size is 16, see wasm-module-builder.cc
     221             :     static const int kExpectedValue = 16;
     222           5 :     TestSignatures sigs;
     223           5 :     v8::internal::AccountingAllocator allocator;
     224          10 :     Zone zone(&allocator, ZONE_NAME);
     225             : 
     226           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     227           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     228           5 :     ExportAsMain(f);
     229           5 :     byte code[] = {WASM_MEMORY_SIZE};
     230           5 :     EMIT_CODE_WITH_END(f, code);
     231          10 :     TestModule(&zone, builder, kExpectedValue);
     232             :   }
     233           5 :   Cleanup();
     234           5 : }
     235             : 
     236       28342 : TEST(Run_WasmModule_MemSize_GrowMem) {
     237             :   {
     238             :     // Initial memory size = 16 + MemoryGrow(10)
     239             :     static const int kExpectedValue = 26;
     240           5 :     TestSignatures sigs;
     241           5 :     v8::internal::AccountingAllocator allocator;
     242          10 :     Zone zone(&allocator, ZONE_NAME);
     243             : 
     244           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     245           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     246           5 :     ExportAsMain(f);
     247             :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(10)), WASM_DROP,
     248           5 :                    WASM_MEMORY_SIZE};
     249           5 :     EMIT_CODE_WITH_END(f, code);
     250          10 :     TestModule(&zone, builder, kExpectedValue);
     251             :   }
     252           5 :   Cleanup();
     253           5 : }
     254             : 
     255       28342 : TEST(MemoryGrowZero) {
     256             :   {
     257             :     // Initial memory size is 16, see wasm-module-builder.cc
     258             :     static const int kExpectedValue = 16;
     259           5 :     TestSignatures sigs;
     260           5 :     v8::internal::AccountingAllocator allocator;
     261          10 :     Zone zone(&allocator, ZONE_NAME);
     262             : 
     263           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     264           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     265           5 :     ExportAsMain(f);
     266           5 :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V(0))};
     267           5 :     EMIT_CODE_WITH_END(f, code);
     268          10 :     TestModule(&zone, builder, kExpectedValue);
     269             :   }
     270           5 :   Cleanup();
     271           5 : }
     272             : 
     273           5 : class InterruptThread : public v8::base::Thread {
     274             :  public:
     275             :   explicit InterruptThread(Isolate* isolate, int32_t* memory)
     276             :       : Thread(Options("TestInterruptLoop")),
     277             :         isolate_(isolate),
     278           5 :         memory_(memory) {}
     279             : 
     280           5 :   static void OnInterrupt(v8::Isolate* isolate, void* data) {
     281             :     int32_t* m = reinterpret_cast<int32_t*>(data);
     282             :     // Set the interrupt location to 0 to break the loop in {TestInterruptLoop}.
     283             :     Address ptr = reinterpret_cast<Address>(&m[interrupt_location_]);
     284             :     WriteLittleEndianValue<int32_t>(ptr, interrupt_value_);
     285           5 :   }
     286             : 
     287           5 :   void Run() override {
     288             :     // Wait for the main thread to write the signal value.
     289           5 :     int32_t val = 0;
     290           5 :     do {
     291           5 :       val = memory_[0];
     292             :       val = ReadLittleEndianValue<int32_t>(reinterpret_cast<Address>(&val));
     293             :     } while (val != signal_value_);
     294           5 :     isolate_->RequestInterrupt(&OnInterrupt, const_cast<int32_t*>(memory_));
     295           5 :   }
     296             : 
     297             :   Isolate* isolate_;
     298             :   volatile int32_t* memory_;
     299             :   static const int32_t interrupt_location_ = 10;
     300             :   static const int32_t interrupt_value_ = 154;
     301             :   static const int32_t signal_value_ = 1221;
     302             : };
     303             : 
     304       28342 : TEST(TestInterruptLoop) {
     305             :   {
     306             :     // Do not dump the module of this test because it contains an infinite loop.
     307           5 :     if (FLAG_dump_wasm_module) return;
     308             : 
     309             :     // This test tests that WebAssembly loops can be interrupted, i.e. that if
     310             :     // an
     311             :     // InterruptCallback is registered by {Isolate::RequestInterrupt}, then the
     312             :     // InterruptCallback is eventually called even if a loop in WebAssembly code
     313             :     // is executed.
     314             :     // Test setup:
     315             :     // The main thread executes a WebAssembly function with a loop. In the loop
     316             :     // {signal_value_} is written to memory to signal a helper thread that the
     317             :     // main thread reached the loop in the WebAssembly program. When the helper
     318             :     // thread reads {signal_value_} from memory, it registers the
     319             :     // InterruptCallback. Upon exeution, the InterruptCallback write into the
     320             :     // WebAssemblyMemory to end the loop in the WebAssembly program.
     321           5 :     TestSignatures sigs;
     322           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     323           5 :     v8::internal::AccountingAllocator allocator;
     324          10 :     Zone zone(&allocator, ZONE_NAME);
     325             : 
     326           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     327           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     328           5 :     ExportAsMain(f);
     329             :     byte code[] = {
     330          10 :         WASM_LOOP(
     331             :             WASM_IFB(WASM_NOT(WASM_LOAD_MEM(
     332             :                          MachineType::Int32(),
     333             :                          WASM_I32V(InterruptThread::interrupt_location_ * 4))),
     334             :                      WASM_STORE_MEM(MachineType::Int32(), WASM_ZERO,
     335             :                                     WASM_I32V(InterruptThread::signal_value_)),
     336             :                      WASM_BR(1))),
     337          15 :         WASM_I32V(121)};
     338           5 :     EMIT_CODE_WITH_END(f, code);
     339             :     ZoneBuffer buffer(&zone);
     340           5 :     builder->WriteTo(buffer);
     341             : 
     342             :     HandleScope scope(isolate);
     343           5 :     testing::SetupIsolateForWasmModule(isolate);
     344           5 :     ErrorThrower thrower(isolate, "Test");
     345             :     const Handle<WasmInstanceObject> instance =
     346             :         CompileAndInstantiateForTesting(
     347          10 :             isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
     348          10 :             .ToHandleChecked();
     349             : 
     350          10 :     Handle<JSArrayBuffer> memory(instance->memory_object()->array_buffer(),
     351          10 :                                  isolate);
     352             :     int32_t* memory_array = reinterpret_cast<int32_t*>(memory->backing_store());
     353             : 
     354             :     InterruptThread thread(isolate, memory_array);
     355           5 :     thread.Start();
     356           5 :     testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
     357             :     Address address = reinterpret_cast<Address>(
     358             :         &memory_array[InterruptThread::interrupt_location_]);
     359           5 :     CHECK_EQ(InterruptThread::interrupt_value_,
     360           5 :              ReadLittleEndianValue<int32_t>(address));
     361             :   }
     362           5 :   Cleanup();
     363             : }
     364             : 
     365       28342 : TEST(Run_WasmModule_MemoryGrowInIf) {
     366             :   {
     367           5 :     TestSignatures sigs;
     368           5 :     v8::internal::AccountingAllocator allocator;
     369          10 :     Zone zone(&allocator, ZONE_NAME);
     370           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     371           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     372           5 :     ExportAsMain(f);
     373             :     byte code[] = {WASM_IF_ELSE_I(WASM_I32V(0), WASM_GROW_MEMORY(WASM_I32V(1)),
     374           5 :                                   WASM_I32V(12))};
     375           5 :     EMIT_CODE_WITH_END(f, code);
     376          10 :     TestModule(&zone, builder, 12);
     377             :   }
     378           5 :   Cleanup();
     379           5 : }
     380             : 
     381       28342 : TEST(Run_WasmModule_GrowMemOobOffset) {
     382             :   {
     383             :     static const int kPageSize = 0x10000;
     384             :     // Initial memory size = 16 + MemoryGrow(10)
     385             :     static const int index = kPageSize * 17 + 4;
     386             :     int value = 0xACED;
     387           5 :     TestSignatures sigs;
     388           5 :     v8::internal::AccountingAllocator allocator;
     389          10 :     Zone zone(&allocator, ZONE_NAME);
     390             : 
     391           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     392           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     393           5 :     ExportAsMain(f);
     394             :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(1)),
     395           5 :                    WASM_STORE_MEM(MachineType::Int32(), WASM_I32V(index),
     396          10 :                                   WASM_I32V(value))};
     397           5 :     EMIT_CODE_WITH_END(f, code);
     398          10 :     TestModuleException(&zone, builder);
     399             :   }
     400           5 :   Cleanup();
     401           5 : }
     402             : 
     403       28342 : TEST(Run_WasmModule_GrowMemOobFixedIndex) {
     404             :   {
     405             :     static const int kPageSize = 0x10000;
     406             :     // Initial memory size = 16 + MemoryGrow(10)
     407             :     static const int index = kPageSize * 26 + 4;
     408             :     int value = 0xACED;
     409           5 :     TestSignatures sigs;
     410           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     411           5 :     Zone zone(isolate->allocator(), ZONE_NAME);
     412             : 
     413           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     414           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
     415           5 :     ExportAsMain(f);
     416             :     byte code[] = {WASM_GROW_MEMORY(WASM_GET_LOCAL(0)), WASM_DROP,
     417           5 :                    WASM_STORE_MEM(MachineType::Int32(), WASM_I32V(index),
     418             :                                   WASM_I32V(value)),
     419          10 :                    WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V(index))};
     420           5 :     EMIT_CODE_WITH_END(f, code);
     421             : 
     422             :     HandleScope scope(isolate);
     423             :     ZoneBuffer buffer(&zone);
     424           5 :     builder->WriteTo(buffer);
     425           5 :     testing::SetupIsolateForWasmModule(isolate);
     426             : 
     427           5 :     ErrorThrower thrower(isolate, "Test");
     428             :     Handle<WasmInstanceObject> instance =
     429             :         CompileAndInstantiateForTesting(
     430          10 :             isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
     431          10 :             .ToHandleChecked();
     432             : 
     433             :     // Initial memory size is 16 pages, should trap till index > MemSize on
     434             :     // consecutive GrowMem calls
     435          25 :     for (uint32_t i = 1; i < 5; i++) {
     436          20 :       Handle<Object> params[1] = {Handle<Object>(Smi::FromInt(i), isolate)};
     437          20 :       v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     438          20 :       testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     439          20 :       CHECK(try_catch.HasCaught());
     440          20 :       isolate->clear_pending_exception();
     441          20 :     }
     442             : 
     443             :     Handle<Object> params[1] = {Handle<Object>(Smi::FromInt(1), isolate)};
     444             :     int32_t result =
     445           5 :         testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     446          10 :     CHECK_EQ(0xACED, result);
     447             :   }
     448           5 :   Cleanup();
     449           5 : }
     450             : 
     451       28342 : TEST(Run_WasmModule_GrowMemOobVariableIndex) {
     452             :   {
     453             :     static const int kPageSize = 0x10000;
     454             :     int value = 0xACED;
     455           5 :     TestSignatures sigs;
     456           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     457           5 :     v8::internal::AccountingAllocator allocator;
     458          10 :     Zone zone(&allocator, ZONE_NAME);
     459             : 
     460           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     461           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
     462           5 :     ExportAsMain(f);
     463             :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(1)), WASM_DROP,
     464           5 :                    WASM_STORE_MEM(MachineType::Int32(), WASM_GET_LOCAL(0),
     465             :                                   WASM_I32V(value)),
     466          10 :                    WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0))};
     467           5 :     EMIT_CODE_WITH_END(f, code);
     468             : 
     469             :     HandleScope scope(isolate);
     470             :     ZoneBuffer buffer(&zone);
     471           5 :     builder->WriteTo(buffer);
     472           5 :     testing::SetupIsolateForWasmModule(isolate);
     473             : 
     474           5 :     ErrorThrower thrower(isolate, "Test");
     475             :     Handle<WasmInstanceObject> instance =
     476             :         CompileAndInstantiateForTesting(
     477          10 :             isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
     478          10 :             .ToHandleChecked();
     479             : 
     480             :     // Initial memory size is 16 pages, should trap till index > MemSize on
     481             :     // consecutive GrowMem calls
     482          25 :     for (int i = 1; i < 5; i++) {
     483             :       Handle<Object> params[1] = {
     484          20 :           Handle<Object>(Smi::FromInt((16 + i) * kPageSize - 3), isolate)};
     485          20 :       v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     486          20 :       testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     487          20 :       CHECK(try_catch.HasCaught());
     488          20 :       isolate->clear_pending_exception();
     489          20 :     }
     490             : 
     491          20 :     for (int i = 1; i < 5; i++) {
     492             :       Handle<Object> params[1] = {
     493          20 :           Handle<Object>(Smi::FromInt((20 + i) * kPageSize - 4), isolate)};
     494             :       int32_t result =
     495          20 :           testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     496          20 :       CHECK_EQ(0xACED, result);
     497             :     }
     498             : 
     499          10 :     v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     500             :     Handle<Object> params[1] = {
     501             :         Handle<Object>(Smi::FromInt(25 * kPageSize), isolate)};
     502           5 :     testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     503           5 :     CHECK(try_catch.HasCaught());
     504          10 :     isolate->clear_pending_exception();
     505             :   }
     506           5 :   Cleanup();
     507           5 : }
     508             : 
     509       28342 : TEST(Run_WasmModule_Global_init) {
     510             :   {
     511           5 :     v8::internal::AccountingAllocator allocator;
     512          10 :     Zone zone(&allocator, ZONE_NAME);
     513           5 :     TestSignatures sigs;
     514             : 
     515           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     516             :     uint32_t global1 =
     517           5 :         builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(777777));
     518             :     uint32_t global2 =
     519           5 :         builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(222222));
     520           5 :     WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_v());
     521             :     byte code[] = {
     522           5 :         WASM_I32_ADD(WASM_GET_GLOBAL(global1), WASM_GET_GLOBAL(global2))};
     523           5 :     EMIT_CODE_WITH_END(f1, code);
     524           5 :     ExportAsMain(f1);
     525          10 :     TestModule(&zone, builder, 999999);
     526             :   }
     527           5 :   Cleanup();
     528           5 : }
     529             : 
     530             : template <typename CType>
     531          30 : static void RunWasmModuleGlobalInitTest(ValueType type, CType expected) {
     532             :   {
     533          30 :     v8::internal::AccountingAllocator allocator;
     534          60 :     Zone zone(&allocator, ZONE_NAME);
     535          30 :     TestSignatures sigs;
     536             : 
     537          30 :     ValueType types[] = {type};
     538             :     FunctionSig sig(1, 0, types);
     539             : 
     540         180 :     for (int padding = 0; padding < 5; padding++) {
     541             :       // Test with a simple initializer
     542         150 :       WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     543             : 
     544         450 :       for (int i = 0; i < padding; i++) {  // pad global before
     545         600 :         builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(i + 20000));
     546             :       }
     547             :       uint32_t global =
     548         150 :           builder->AddGlobal(type, false, false, WasmInitExpr(expected));
     549         450 :       for (int i = 0; i < padding; i++) {  // pad global after
     550         600 :         builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(i + 30000));
     551             :       }
     552             : 
     553         150 :       WasmFunctionBuilder* f1 = builder->AddFunction(&sig);
     554         150 :       byte code[] = {WASM_GET_GLOBAL(global)};
     555         150 :       EMIT_CODE_WITH_END(f1, code);
     556         150 :       ExportAsMain(f1);
     557         150 :       TestModule(&zone, builder, expected);
     558          30 :     }
     559             :   }
     560          30 :   Cleanup();
     561          30 : }
     562             : 
     563       28342 : TEST(Run_WasmModule_Global_i32) {
     564           5 :   RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, -983489);
     565           5 :   RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, 11223344);
     566           5 : }
     567             : 
     568       28342 : TEST(Run_WasmModule_Global_f32) {
     569           5 :   RunWasmModuleGlobalInitTest<float>(kWasmF32, -983.9f);
     570           5 :   RunWasmModuleGlobalInitTest<float>(kWasmF32, 1122.99f);
     571           5 : }
     572             : 
     573       28342 : TEST(Run_WasmModule_Global_f64) {
     574           5 :   RunWasmModuleGlobalInitTest<double>(kWasmF64, -833.9);
     575           5 :   RunWasmModuleGlobalInitTest<double>(kWasmF64, 86374.25);
     576           5 : }
     577             : 
     578       28342 : TEST(InitDataAtTheUpperLimit) {
     579             :   {
     580           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     581             :     HandleScope scope(isolate);
     582           5 :     testing::SetupIsolateForWasmModule(isolate);
     583             : 
     584           5 :     ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
     585             : 
     586             :     const byte data[] = {
     587             :         WASM_MODULE_HEADER,   // --
     588             :         kMemorySectionCode,   // --
     589             :         U32V_1(4),            // section size
     590             :         ENTRY_COUNT(1),       // --
     591             :         kHasMaximumFlag,      // --
     592             :         1,                    // initial size
     593             :         2,                    // maximum size
     594             :         kDataSectionCode,     // --
     595             :         U32V_1(9),            // section size
     596             :         ENTRY_COUNT(1),       // --
     597             :         0,                    // linear memory index
     598             :         WASM_I32V_3(0xFFFF),  // destination offset
     599             :         kExprEnd,
     600             :         U32V_1(1),  // source size
     601             :         'c'         // data bytes
     602           5 :     };
     603             : 
     604             :     CompileAndInstantiateForTesting(
     605           5 :         isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
     606           5 :     if (thrower.error()) {
     607           0 :       thrower.Reify()->Print();
     608           0 :       FATAL("compile or instantiate error");
     609             :     }
     610             :   }
     611           5 :   Cleanup();
     612           5 : }
     613             : 
     614       28342 : TEST(EmptyMemoryNonEmptyDataSegment) {
     615             :   {
     616           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     617             :     HandleScope scope(isolate);
     618           5 :     testing::SetupIsolateForWasmModule(isolate);
     619             : 
     620           5 :     ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
     621             : 
     622             :     const byte data[] = {
     623             :         WASM_MODULE_HEADER,  // --
     624             :         kMemorySectionCode,  // --
     625             :         U32V_1(4),           // section size
     626             :         ENTRY_COUNT(1),      // --
     627             :         kHasMaximumFlag,     // --
     628             :         0,                   // initial size
     629             :         0,                   // maximum size
     630             :         kDataSectionCode,    // --
     631             :         U32V_1(7),           // section size
     632             :         ENTRY_COUNT(1),      // --
     633             :         0,                   // linear memory index
     634             :         WASM_I32V_1(8),      // destination offset
     635             :         kExprEnd,
     636             :         U32V_1(1),  // source size
     637             :         'c'         // data bytes
     638           5 :     };
     639             : 
     640             :     CompileAndInstantiateForTesting(
     641           5 :         isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
     642             :     // It should not be possible to instantiate this module.
     643           5 :     CHECK(thrower.error());
     644             :   }
     645           5 :   Cleanup();
     646           5 : }
     647             : 
     648       28342 : TEST(EmptyMemoryEmptyDataSegment) {
     649             :   {
     650           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     651             :     HandleScope scope(isolate);
     652           5 :     testing::SetupIsolateForWasmModule(isolate);
     653             : 
     654           5 :     ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
     655             : 
     656             :     const byte data[] = {
     657             :         WASM_MODULE_HEADER,  // --
     658             :         kMemorySectionCode,  // --
     659             :         U32V_1(4),           // section size
     660             :         ENTRY_COUNT(1),      // --
     661             :         kHasMaximumFlag,     // --
     662             :         0,                   // initial size
     663             :         0,                   // maximum size
     664             :         kDataSectionCode,    // --
     665             :         U32V_1(6),           // section size
     666             :         ENTRY_COUNT(1),      // --
     667             :         0,                   // linear memory index
     668             :         WASM_I32V_1(0),      // destination offset
     669             :         kExprEnd,
     670             :         U32V_1(0),  // source size
     671           5 :     };
     672             : 
     673             :     CompileAndInstantiateForTesting(
     674           5 :         isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
     675             :     // It should be possible to instantiate this module.
     676          10 :     CHECK(!thrower.error());
     677             :   }
     678           5 :   Cleanup();
     679           5 : }
     680             : 
     681       28342 : TEST(MemoryWithOOBEmptyDataSegment) {
     682             :   {
     683           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     684             :     HandleScope scope(isolate);
     685           5 :     testing::SetupIsolateForWasmModule(isolate);
     686             : 
     687           5 :     ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
     688             : 
     689             :     const byte data[] = {
     690             :         WASM_MODULE_HEADER,      // --
     691             :         kMemorySectionCode,      // --
     692             :         U32V_1(4),               // section size
     693             :         ENTRY_COUNT(1),          // --
     694             :         kHasMaximumFlag,         // --
     695             :         1,                       // initial size
     696             :         1,                       // maximum size
     697             :         kDataSectionCode,        // --
     698             :         U32V_1(9),               // section size
     699             :         ENTRY_COUNT(1),          // --
     700             :         0,                       // linear memory index
     701             :         WASM_I32V_4(0x2468ACE),  // destination offset
     702             :         kExprEnd,
     703             :         U32V_1(0),  // source size
     704           5 :     };
     705             : 
     706             :     CompileAndInstantiateForTesting(
     707           5 :         isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
     708             :     // It should not be possible to instantiate this module.
     709           5 :     CHECK(thrower.error());
     710             :   }
     711           5 :   Cleanup();
     712           5 : }
     713             : 
     714             : // Utility to free the allocated memory for a buffer that is manually
     715             : // externalized in a test.
     716             : struct ManuallyExternalizedBuffer {
     717             :   Isolate* isolate_;
     718             :   Handle<JSArrayBuffer> buffer_;
     719             :   void* allocation_base_;
     720             :   size_t allocation_length_;
     721             :   bool const should_free_;
     722             : 
     723          10 :   ManuallyExternalizedBuffer(JSArrayBuffer buffer, Isolate* isolate)
     724             :       : isolate_(isolate),
     725             :         buffer_(buffer, isolate),
     726          10 :         allocation_base_(buffer->allocation_base()),
     727          10 :         allocation_length_(buffer->allocation_length()),
     728             :         should_free_(!isolate_->wasm_engine()->memory_tracker()->IsWasmMemory(
     729          50 :             buffer->backing_store())) {
     730          10 :     if (!isolate_->wasm_engine()->memory_tracker()->IsWasmMemory(
     731          20 :             buffer->backing_store())) {
     732           0 :       v8::Utils::ToLocal(buffer_)->Externalize();
     733             :     }
     734          10 :   }
     735          10 :   ~ManuallyExternalizedBuffer() {
     736          10 :     if (should_free_) {
     737           0 :       buffer_->FreeBackingStoreFromMainThread();
     738             :     }
     739          10 :   }
     740             : };
     741             : 
     742       28342 : TEST(Run_WasmModule_Buffer_Externalized_GrowMem) {
     743             :   {
     744           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     745             :     HandleScope scope(isolate);
     746           5 :     TestSignatures sigs;
     747          10 :     v8::internal::AccountingAllocator allocator;
     748          10 :     Zone zone(&allocator, ZONE_NAME);
     749             : 
     750           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     751           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     752           5 :     ExportAsMain(f);
     753             :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(6)), WASM_DROP,
     754           5 :                    WASM_MEMORY_SIZE};
     755           5 :     EMIT_CODE_WITH_END(f, code);
     756             : 
     757             :     ZoneBuffer buffer(&zone);
     758           5 :     builder->WriteTo(buffer);
     759           5 :     testing::SetupIsolateForWasmModule(isolate);
     760           5 :     ErrorThrower thrower(isolate, "Test");
     761             :     const Handle<WasmInstanceObject> instance =
     762             :         CompileAndInstantiateForTesting(
     763          10 :             isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
     764          10 :             .ToHandleChecked();
     765          10 :     Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate);
     766             : 
     767             :     // Fake the Embedder flow by externalizing the array buffer.
     768          10 :     ManuallyExternalizedBuffer buffer1(memory_object->array_buffer(), isolate);
     769             : 
     770             :     // Grow using the API.
     771           5 :     uint32_t result = WasmMemoryObject::Grow(isolate, memory_object, 4);
     772           5 :     CHECK_EQ(16, result);
     773           5 :     CHECK(buffer1.buffer_->was_detached());  // growing always detaches
     774           5 :     CHECK_EQ(0, buffer1.buffer_->byte_length());
     775             : 
     776          15 :     CHECK_NE(*buffer1.buffer_, memory_object->array_buffer());
     777             : 
     778             :     // Fake the Embedder flow by externalizing the array buffer.
     779          10 :     ManuallyExternalizedBuffer buffer2(memory_object->array_buffer(), isolate);
     780             : 
     781             :     // Grow using an internal WASM bytecode.
     782           5 :     result = testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
     783           5 :     CHECK_EQ(26, result);
     784           5 :     CHECK(buffer2.buffer_->was_detached());  // growing always detaches
     785           5 :     CHECK_EQ(0, buffer2.buffer_->byte_length());
     786          15 :     CHECK_NE(*buffer2.buffer_, memory_object->array_buffer());
     787             :   }
     788           5 :   Cleanup();
     789           5 : }
     790             : 
     791       28342 : TEST(Run_WasmModule_Buffer_Externalized_GrowMemMemSize) {
     792             :   {
     793           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     794             :     HandleScope scope(isolate);
     795             :     Handle<JSArrayBuffer> buffer;
     796          10 :     CHECK(wasm::NewArrayBuffer(isolate, 16 * kWasmPageSize).ToHandle(&buffer));
     797             :     Handle<WasmMemoryObject> mem_obj =
     798           5 :         WasmMemoryObject::New(isolate, buffer, 100);
     799           5 :     auto const contents = v8::Utils::ToLocal(buffer)->Externalize();
     800           5 :     int32_t result = WasmMemoryObject::Grow(isolate, mem_obj, 0);
     801           5 :     CHECK_EQ(16, result);
     802             :     constexpr bool is_wasm_memory = true;
     803             :     const JSArrayBuffer::Allocation allocation{contents.AllocationBase(),
     804             :                                                contents.AllocationLength(),
     805           5 :                                                contents.Data(), is_wasm_memory};
     806           5 :     JSArrayBuffer::FreeBackingStore(isolate, allocation);
     807             :   }
     808           5 :   Cleanup();
     809           5 : }
     810             : 
     811       28342 : TEST(Run_WasmModule_Buffer_Externalized_Detach) {
     812             :   {
     813             :     // Regression test for
     814             :     // https://bugs.chromium.org/p/chromium/issues/detail?id=731046
     815           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     816             :     HandleScope scope(isolate);
     817             :     Handle<JSArrayBuffer> buffer;
     818          10 :     CHECK(wasm::NewArrayBuffer(isolate, 16 * kWasmPageSize).ToHandle(&buffer));
     819           5 :     auto const contents = v8::Utils::ToLocal(buffer)->Externalize();
     820           5 :     wasm::DetachMemoryBuffer(isolate, buffer, true);
     821             :     constexpr bool is_wasm_memory = true;
     822             :     const JSArrayBuffer::Allocation allocation{contents.AllocationBase(),
     823             :                                                contents.AllocationLength(),
     824           5 :                                                contents.Data(), is_wasm_memory};
     825           5 :     JSArrayBuffer::FreeBackingStore(isolate, allocation);
     826             :   }
     827           5 :   Cleanup();
     828           5 : }
     829             : 
     830       28342 : TEST(Run_WasmModule_Buffer_Externalized_Regression_UseAfterFree) {
     831             :   // Regresion test for https://crbug.com/813876
     832           5 :   Isolate* isolate = CcTest::InitIsolateOnce();
     833             :   HandleScope scope(isolate);
     834             :   Handle<JSArrayBuffer> buffer;
     835          10 :   CHECK(wasm::NewArrayBuffer(isolate, 16 * kWasmPageSize).ToHandle(&buffer));
     836           5 :   Handle<WasmMemoryObject> mem = WasmMemoryObject::New(isolate, buffer, 128);
     837           5 :   auto contents = v8::Utils::ToLocal(buffer)->Externalize();
     838           5 :   WasmMemoryObject::Grow(isolate, mem, 0);
     839             :   constexpr bool is_wasm_memory = true;
     840             :   JSArrayBuffer::FreeBackingStore(
     841             :       isolate, JSArrayBuffer::Allocation(contents.AllocationBase(),
     842             :                                          contents.AllocationLength(),
     843          10 :                                          contents.Data(), is_wasm_memory));
     844             :   // Make sure we can write to the buffer without crashing
     845             :   uint32_t* int_buffer =
     846          10 :       reinterpret_cast<uint32_t*>(mem->array_buffer()->backing_store());
     847           5 :   int_buffer[0] = 0;
     848           5 : }
     849             : 
     850             : #if V8_TARGET_ARCH_64_BIT
     851       28342 : TEST(Run_WasmModule_Reclaim_Memory) {
     852             :   // Make sure we can allocate memories without running out of address space.
     853           5 :   Isolate* isolate = CcTest::InitIsolateOnce();
     854             :   Handle<JSArrayBuffer> buffer;
     855        1285 :   for (int i = 0; i < 256; ++i) {
     856             :     HandleScope scope(isolate);
     857        2560 :     CHECK(NewArrayBuffer(isolate, kWasmPageSize, SharedFlag::kNotShared)
     858             :               .ToHandle(&buffer));
     859             :   }
     860           5 : }
     861             : #endif
     862             : 
     863       28342 : TEST(AtomicOpDisassembly) {
     864             :   {
     865             :     EXPERIMENTAL_FLAG_SCOPE(threads);
     866           5 :     TestSignatures sigs;
     867           5 :     Isolate* isolate = CcTest::InitIsolateOnce();
     868          10 :     v8::internal::AccountingAllocator allocator;
     869          10 :     Zone zone(&allocator, ZONE_NAME);
     870             : 
     871           5 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     872           5 :     builder->SetHasSharedMemory();
     873           5 :     builder->SetMaxMemorySize(16);
     874           5 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
     875           5 :     ExportAsMain(f);
     876             :     byte code[] = {
     877           5 :         WASM_ATOMICS_STORE_OP(kExprI32AtomicStore, WASM_ZERO, WASM_GET_LOCAL(0),
     878             :                               MachineRepresentation::kWord32),
     879           5 :         WASM_ATOMICS_LOAD_OP(kExprI32AtomicLoad, WASM_ZERO,
     880          15 :                              MachineRepresentation::kWord32)};
     881           5 :     EMIT_CODE_WITH_END(f, code);
     882             : 
     883             :     HandleScope scope(isolate);
     884             :     ZoneBuffer buffer(&zone);
     885           5 :     builder->WriteTo(buffer);
     886           5 :     testing::SetupIsolateForWasmModule(isolate);
     887             : 
     888           5 :     ErrorThrower thrower(isolate, "Test");
     889           5 :     auto enabled_features = WasmFeaturesFromIsolate(isolate);
     890             :     MaybeHandle<WasmModuleObject> module_object =
     891             :         isolate->wasm_engine()->SyncCompile(
     892             :             isolate, enabled_features, &thrower,
     893          10 :             ModuleWireBytes(buffer.begin(), buffer.end()));
     894             : 
     895           5 :     module_object.ToHandleChecked()->DisassembleFunction(0);
     896             :   }
     897           5 :   Cleanup();
     898           5 : }
     899             : 
     900             : #undef EMIT_CODE_WITH_END
     901             : 
     902             : }  // namespace test_run_wasm_module
     903             : }  // namespace wasm
     904             : }  // namespace internal
     905       85011 : }  // namespace v8

Generated by: LCOV version 1.10