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: 367 371 98.9 %
Date: 2019-04-17 Functions: 38 40 95.0 %

          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         116 :   reinterpret_cast<v8::Isolate*>(isolate)->LowMemoryNotification();
      39             : }
      40             : 
      41         164 : void TestModule(Zone* zone, WasmModuleBuilder* builder,
      42             :                 int32_t expected_result) {
      43             :   ZoneBuffer buffer(zone);
      44         164 :   builder->WriteTo(buffer);
      45             : 
      46             :   Isolate* isolate = CcTest::InitIsolateOnce();
      47             :   HandleScope scope(isolate);
      48         164 :   testing::SetupIsolateForWasmModule(isolate);
      49             :   int32_t result =
      50         164 :       testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
      51         164 :   CHECK_EQ(expected_result, result);
      52         164 : }
      53             : 
      54           4 : void TestModuleException(Zone* zone, WasmModuleBuilder* builder) {
      55             :   ZoneBuffer buffer(zone);
      56           4 :   builder->WriteTo(buffer);
      57             : 
      58             :   Isolate* isolate = CcTest::InitIsolateOnce();
      59             :   HandleScope scope(isolate);
      60           4 :   testing::SetupIsolateForWasmModule(isolate);
      61           8 :   v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
      62           4 :   testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
      63           4 :   CHECK(try_catch.HasCaught());
      64             :   isolate->clear_pending_exception();
      65           4 : }
      66             : 
      67             : void ExportAsMain(WasmFunctionBuilder* f) {
      68         188 :   f->builder()->AddExport(CStrVector("main"), f);
      69             : }
      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       26643 : TEST(Run_WasmModule_Return114) {
      80             :   {
      81             :     static const int32_t kReturnValue = 114;
      82           4 :     TestSignatures sigs;
      83           8 :     v8::internal::AccountingAllocator allocator;
      84           8 :     Zone zone(&allocator, ZONE_NAME);
      85             : 
      86           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
      87           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
      88             :     ExportAsMain(f);
      89           4 :     byte code[] = {WASM_I32V_2(kReturnValue)};
      90           4 :     EMIT_CODE_WITH_END(f, code);
      91           4 :     TestModule(&zone, builder, kReturnValue);
      92             :   }
      93             :   Cleanup();
      94           4 : }
      95             : 
      96       26643 : TEST(Run_WasmModule_CallAdd) {
      97             :   {
      98           8 :     v8::internal::AccountingAllocator allocator;
      99           8 :     Zone zone(&allocator, ZONE_NAME);
     100           4 :     TestSignatures sigs;
     101             : 
     102           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     103             : 
     104           4 :     WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_ii());
     105             :     uint16_t param1 = 0;
     106             :     uint16_t param2 = 1;
     107             :     byte code1[] = {
     108           4 :         WASM_I32_ADD(WASM_GET_LOCAL(param1), WASM_GET_LOCAL(param2))};
     109           4 :     EMIT_CODE_WITH_END(f1, code1);
     110             : 
     111           4 :     WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v());
     112             : 
     113             :     ExportAsMain(f2);
     114             :     byte code2[] = {
     115           4 :         WASM_CALL_FUNCTION(f1->func_index(), WASM_I32V_2(77), WASM_I32V_1(22))};
     116           4 :     EMIT_CODE_WITH_END(f2, code2);
     117           4 :     TestModule(&zone, builder, 99);
     118             :   }
     119             :   Cleanup();
     120           4 : }
     121             : 
     122       26643 : TEST(Run_WasmModule_ReadLoadedDataSegment) {
     123             :   {
     124             :     static const byte kDataSegmentDest0 = 12;
     125           8 :     v8::internal::AccountingAllocator allocator;
     126           8 :     Zone zone(&allocator, ZONE_NAME);
     127           4 :     TestSignatures sigs;
     128             : 
     129           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     130           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     131             : 
     132             :     ExportAsMain(f);
     133             :     byte code[] = {
     134           4 :         WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V_1(kDataSegmentDest0))};
     135           4 :     EMIT_CODE_WITH_END(f, code);
     136           4 :     byte data[] = {0xAA, 0xBB, 0xCC, 0xDD};
     137           4 :     builder->AddDataSegment(data, sizeof(data), kDataSegmentDest0);
     138           4 :     TestModule(&zone, builder, 0xDDCCBBAA);
     139             :   }
     140             :   Cleanup();
     141           4 : }
     142             : 
     143       26643 : TEST(Run_WasmModule_CheckMemoryIsZero) {
     144             :   {
     145             :     static const int kCheckSize = 16 * 1024;
     146           8 :     v8::internal::AccountingAllocator allocator;
     147           8 :     Zone zone(&allocator, ZONE_NAME);
     148           4 :     TestSignatures sigs;
     149             : 
     150           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     151           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     152             : 
     153           4 :     uint16_t localIndex = f->AddLocal(kWasmI32);
     154             :     ExportAsMain(f);
     155           4 :     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           8 :         WASM_I32V_1(11))};
     163           4 :     EMIT_CODE_WITH_END(f, code);
     164           4 :     TestModule(&zone, builder, 11);
     165             :   }
     166             :   Cleanup();
     167           4 : }
     168             : 
     169       26643 : TEST(Run_WasmModule_CallMain_recursive) {
     170             :   {
     171           8 :     v8::internal::AccountingAllocator allocator;
     172           8 :     Zone zone(&allocator, ZONE_NAME);
     173           4 :     TestSignatures sigs;
     174             : 
     175           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     176           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     177             : 
     178           4 :     uint16_t localIndex = f->AddLocal(kWasmI32);
     179             :     ExportAsMain(f);
     180             :     byte code[] = {
     181           4 :         WASM_SET_LOCAL(localIndex,
     182             :                        WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO)),
     183           4 :         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          12 :                        WASM_I32V_1(55))};
     188           4 :     EMIT_CODE_WITH_END(f, code);
     189           4 :     TestModule(&zone, builder, 55);
     190             :   }
     191             :   Cleanup();
     192           4 : }
     193             : 
     194       26643 : TEST(Run_WasmModule_Global) {
     195             :   {
     196           8 :     v8::internal::AccountingAllocator allocator;
     197           8 :     Zone zone(&allocator, ZONE_NAME);
     198           4 :     TestSignatures sigs;
     199             : 
     200           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     201           4 :     uint32_t global1 = builder->AddGlobal(kWasmI32, false);
     202           4 :     uint32_t global2 = builder->AddGlobal(kWasmI32, false);
     203           4 :     WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_v());
     204             :     byte code1[] = {
     205           4 :         WASM_I32_ADD(WASM_GET_GLOBAL(global1), WASM_GET_GLOBAL(global2))};
     206           4 :     EMIT_CODE_WITH_END(f1, code1);
     207           4 :     WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v());
     208             :     ExportAsMain(f2);
     209             :     byte code2[] = {WASM_SET_GLOBAL(global1, WASM_I32V_1(56)),
     210             :                     WASM_SET_GLOBAL(global2, WASM_I32V_1(41)),
     211           4 :                     WASM_RETURN1(WASM_CALL_FUNCTION0(f1->func_index()))};
     212           4 :     EMIT_CODE_WITH_END(f2, code2);
     213           4 :     TestModule(&zone, builder, 97);
     214             :   }
     215             :   Cleanup();
     216           4 : }
     217             : 
     218       26643 : TEST(MemorySize) {
     219             :   {
     220             :     // Initial memory size is 16, see wasm-module-builder.cc
     221             :     static const int kExpectedValue = 16;
     222           4 :     TestSignatures sigs;
     223           8 :     v8::internal::AccountingAllocator allocator;
     224           8 :     Zone zone(&allocator, ZONE_NAME);
     225             : 
     226           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     227           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     228             :     ExportAsMain(f);
     229           4 :     byte code[] = {WASM_MEMORY_SIZE};
     230           4 :     EMIT_CODE_WITH_END(f, code);
     231           4 :     TestModule(&zone, builder, kExpectedValue);
     232             :   }
     233             :   Cleanup();
     234           4 : }
     235             : 
     236       26643 : TEST(Run_WasmModule_MemSize_GrowMem) {
     237             :   {
     238             :     // Initial memory size = 16 + MemoryGrow(10)
     239             :     static const int kExpectedValue = 26;
     240           4 :     TestSignatures sigs;
     241           8 :     v8::internal::AccountingAllocator allocator;
     242           8 :     Zone zone(&allocator, ZONE_NAME);
     243             : 
     244           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     245           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     246             :     ExportAsMain(f);
     247             :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(10)), WASM_DROP,
     248           4 :                    WASM_MEMORY_SIZE};
     249           4 :     EMIT_CODE_WITH_END(f, code);
     250           4 :     TestModule(&zone, builder, kExpectedValue);
     251             :   }
     252             :   Cleanup();
     253           4 : }
     254             : 
     255       26643 : TEST(MemoryGrowZero) {
     256             :   {
     257             :     // Initial memory size is 16, see wasm-module-builder.cc
     258             :     static const int kExpectedValue = 16;
     259           4 :     TestSignatures sigs;
     260           8 :     v8::internal::AccountingAllocator allocator;
     261           8 :     Zone zone(&allocator, ZONE_NAME);
     262             : 
     263           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     264           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     265             :     ExportAsMain(f);
     266           4 :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V(0))};
     267           4 :     EMIT_CODE_WITH_END(f, code);
     268           4 :     TestModule(&zone, builder, kExpectedValue);
     269             :   }
     270             :   Cleanup();
     271           4 : }
     272             : 
     273           4 : class InterruptThread : public v8::base::Thread {
     274             :  public:
     275             :   explicit InterruptThread(Isolate* isolate, int32_t* memory)
     276             :       : Thread(Options("TestInterruptLoop")),
     277             :         isolate_(isolate),
     278           4 :         memory_(memory) {}
     279             : 
     280           4 :   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           4 :   }
     286             : 
     287           4 :   void Run() override {
     288             :     // Wait for the main thread to write the signal value.
     289           4 :     int32_t val = 0;
     290             :     do {
     291           4 :       val = memory_[0];
     292             :       val = ReadLittleEndianValue<int32_t>(reinterpret_cast<Address>(&val));
     293           4 :     } while (val != signal_value_);
     294           4 :     isolate_->RequestInterrupt(&OnInterrupt, const_cast<int32_t*>(memory_));
     295           4 :   }
     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       26643 : TEST(TestInterruptLoop) {
     305             :   {
     306             :     // Do not dump the module of this test because it contains an infinite loop.
     307             :     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           4 :     TestSignatures sigs;
     322             :     Isolate* isolate = CcTest::InitIsolateOnce();
     323           8 :     v8::internal::AccountingAllocator allocator;
     324           8 :     Zone zone(&allocator, ZONE_NAME);
     325             : 
     326           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     327           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     328             :     ExportAsMain(f);
     329             :     byte code[] = {
     330           8 :         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          12 :         WASM_I32V(121)};
     338           4 :     EMIT_CODE_WITH_END(f, code);
     339             :     ZoneBuffer buffer(&zone);
     340           4 :     builder->WriteTo(buffer);
     341             : 
     342             :     HandleScope scope(isolate);
     343           4 :     testing::SetupIsolateForWasmModule(isolate);
     344           4 :     ErrorThrower thrower(isolate, "Test");
     345             :     const Handle<WasmInstanceObject> instance =
     346           8 :         CompileAndInstantiateForTesting(
     347           4 :             isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
     348             :             .ToHandleChecked();
     349             : 
     350             :     Handle<JSArrayBuffer> memory(instance->memory_object()->array_buffer(),
     351             :                                  isolate);
     352             :     int32_t* memory_array = reinterpret_cast<int32_t*>(memory->backing_store());
     353             : 
     354             :     InterruptThread thread(isolate, memory_array);
     355           4 :     thread.Start();
     356           4 :     testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
     357             :     Address address = reinterpret_cast<Address>(
     358             :         &memory_array[InterruptThread::interrupt_location_]);
     359           4 :     CHECK_EQ(InterruptThread::interrupt_value_,
     360             :              ReadLittleEndianValue<int32_t>(address));
     361             :   }
     362             :   Cleanup();
     363             : }
     364             : 
     365       26643 : TEST(Run_WasmModule_MemoryGrowInIf) {
     366             :   {
     367           4 :     TestSignatures sigs;
     368           8 :     v8::internal::AccountingAllocator allocator;
     369           8 :     Zone zone(&allocator, ZONE_NAME);
     370           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     371           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     372             :     ExportAsMain(f);
     373             :     byte code[] = {WASM_IF_ELSE_I(WASM_I32V(0), WASM_GROW_MEMORY(WASM_I32V(1)),
     374           4 :                                   WASM_I32V(12))};
     375           4 :     EMIT_CODE_WITH_END(f, code);
     376           4 :     TestModule(&zone, builder, 12);
     377             :   }
     378             :   Cleanup();
     379           4 : }
     380             : 
     381       26643 : 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           4 :     TestSignatures sigs;
     388           8 :     v8::internal::AccountingAllocator allocator;
     389           8 :     Zone zone(&allocator, ZONE_NAME);
     390             : 
     391           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     392           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     393             :     ExportAsMain(f);
     394             :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(1)),
     395           4 :                    WASM_STORE_MEM(MachineType::Int32(), WASM_I32V(index),
     396           8 :                                   WASM_I32V(value))};
     397           4 :     EMIT_CODE_WITH_END(f, code);
     398           4 :     TestModuleException(&zone, builder);
     399             :   }
     400             :   Cleanup();
     401           4 : }
     402             : 
     403       26643 : 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           4 :     TestSignatures sigs;
     410             :     Isolate* isolate = CcTest::InitIsolateOnce();
     411           8 :     Zone zone(isolate->allocator(), ZONE_NAME);
     412             : 
     413           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     414           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
     415             :     ExportAsMain(f);
     416             :     byte code[] = {WASM_GROW_MEMORY(WASM_GET_LOCAL(0)), WASM_DROP,
     417           4 :                    WASM_STORE_MEM(MachineType::Int32(), WASM_I32V(index),
     418             :                                   WASM_I32V(value)),
     419           8 :                    WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V(index))};
     420           4 :     EMIT_CODE_WITH_END(f, code);
     421             : 
     422             :     HandleScope scope(isolate);
     423             :     ZoneBuffer buffer(&zone);
     424           4 :     builder->WriteTo(buffer);
     425           4 :     testing::SetupIsolateForWasmModule(isolate);
     426             : 
     427           4 :     ErrorThrower thrower(isolate, "Test");
     428             :     Handle<WasmInstanceObject> instance =
     429           8 :         CompileAndInstantiateForTesting(
     430           4 :             isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
     431           4 :             .ToHandleChecked();
     432             : 
     433             :     // Initial memory size is 16 pages, should trap till index > MemSize on
     434             :     // consecutive GrowMem calls
     435          36 :     for (uint32_t i = 1; i < 5; i++) {
     436          16 :       Handle<Object> params[1] = {Handle<Object>(Smi::FromInt(i), isolate)};
     437          32 :       v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     438          16 :       testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     439          16 :       CHECK(try_catch.HasCaught());
     440             :       isolate->clear_pending_exception();
     441             :     }
     442             : 
     443             :     Handle<Object> params[1] = {Handle<Object>(Smi::FromInt(1), isolate)};
     444             :     int32_t result =
     445           4 :         testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     446           4 :     CHECK_EQ(0xACED, result);
     447             :   }
     448             :   Cleanup();
     449           4 : }
     450             : 
     451       26643 : TEST(Run_WasmModule_GrowMemOobVariableIndex) {
     452             :   {
     453             :     static const int kPageSize = 0x10000;
     454             :     int value = 0xACED;
     455           4 :     TestSignatures sigs;
     456             :     Isolate* isolate = CcTest::InitIsolateOnce();
     457           8 :     v8::internal::AccountingAllocator allocator;
     458           8 :     Zone zone(&allocator, ZONE_NAME);
     459             : 
     460           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     461           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
     462             :     ExportAsMain(f);
     463             :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(1)), WASM_DROP,
     464           4 :                    WASM_STORE_MEM(MachineType::Int32(), WASM_GET_LOCAL(0),
     465             :                                   WASM_I32V(value)),
     466           8 :                    WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0))};
     467           4 :     EMIT_CODE_WITH_END(f, code);
     468             : 
     469             :     HandleScope scope(isolate);
     470             :     ZoneBuffer buffer(&zone);
     471           4 :     builder->WriteTo(buffer);
     472           4 :     testing::SetupIsolateForWasmModule(isolate);
     473             : 
     474           4 :     ErrorThrower thrower(isolate, "Test");
     475             :     Handle<WasmInstanceObject> instance =
     476           8 :         CompileAndInstantiateForTesting(
     477           4 :             isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
     478           4 :             .ToHandleChecked();
     479             : 
     480             :     // Initial memory size is 16 pages, should trap till index > MemSize on
     481             :     // consecutive GrowMem calls
     482          36 :     for (int i = 1; i < 5; i++) {
     483             :       Handle<Object> params[1] = {
     484          16 :           Handle<Object>(Smi::FromInt((16 + i) * kPageSize - 3), isolate)};
     485          32 :       v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     486          16 :       testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     487          16 :       CHECK(try_catch.HasCaught());
     488             :       isolate->clear_pending_exception();
     489             :     }
     490             : 
     491          36 :     for (int i = 1; i < 5; i++) {
     492             :       Handle<Object> params[1] = {
     493          16 :           Handle<Object>(Smi::FromInt((20 + i) * kPageSize - 4), isolate)};
     494             :       int32_t result =
     495          16 :           testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     496          16 :       CHECK_EQ(0xACED, result);
     497             :     }
     498             : 
     499           8 :     v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     500             :     Handle<Object> params[1] = {
     501             :         Handle<Object>(Smi::FromInt(25 * kPageSize), isolate)};
     502           4 :     testing::RunWasmModuleForTesting(isolate, instance, 1, params);
     503           4 :     CHECK(try_catch.HasCaught());
     504             :     isolate->clear_pending_exception();
     505             :   }
     506             :   Cleanup();
     507           4 : }
     508             : 
     509       26643 : TEST(Run_WasmModule_Global_init) {
     510             :   {
     511           8 :     v8::internal::AccountingAllocator allocator;
     512           8 :     Zone zone(&allocator, ZONE_NAME);
     513           4 :     TestSignatures sigs;
     514             : 
     515           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     516             :     uint32_t global1 =
     517           4 :         builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(777777));
     518             :     uint32_t global2 =
     519           4 :         builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(222222));
     520           4 :     WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_v());
     521             :     byte code[] = {
     522           4 :         WASM_I32_ADD(WASM_GET_GLOBAL(global1), WASM_GET_GLOBAL(global2))};
     523           4 :     EMIT_CODE_WITH_END(f1, code);
     524             :     ExportAsMain(f1);
     525           4 :     TestModule(&zone, builder, 999999);
     526             :   }
     527             :   Cleanup();
     528           4 : }
     529             : 
     530             : template <typename CType>
     531          24 : static void RunWasmModuleGlobalInitTest(ValueType type, CType expected) {
     532             :   {
     533          48 :     v8::internal::AccountingAllocator allocator;
     534          48 :     Zone zone(&allocator, ZONE_NAME);
     535          24 :     TestSignatures sigs;
     536             : 
     537          24 :     ValueType types[] = {type};
     538             :     FunctionSig sig(1, 0, types);
     539             : 
     540         264 :     for (int padding = 0; padding < 5; padding++) {
     541             :       // Test with a simple initializer
     542         120 :       WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     543             : 
     544         600 :       for (int i = 0; i < padding; i++) {  // pad global before
     545         480 :         builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(i + 20000));
     546             :       }
     547             :       uint32_t global =
     548         120 :           builder->AddGlobal(type, false, false, WasmInitExpr(expected));
     549         600 :       for (int i = 0; i < padding; i++) {  // pad global after
     550         480 :         builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(i + 30000));
     551             :       }
     552             : 
     553         120 :       WasmFunctionBuilder* f1 = builder->AddFunction(&sig);
     554         120 :       byte code[] = {WASM_GET_GLOBAL(global)};
     555         120 :       EMIT_CODE_WITH_END(f1, code);
     556             :       ExportAsMain(f1);
     557         120 :       TestModule(&zone, builder, expected);
     558             :     }
     559             :   }
     560             :   Cleanup();
     561          24 : }
     562             : 
     563       26643 : TEST(Run_WasmModule_Global_i32) {
     564           4 :   RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, -983489);
     565           4 :   RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, 11223344);
     566           4 : }
     567             : 
     568       26643 : TEST(Run_WasmModule_Global_f32) {
     569           4 :   RunWasmModuleGlobalInitTest<float>(kWasmF32, -983.9f);
     570           4 :   RunWasmModuleGlobalInitTest<float>(kWasmF32, 1122.99f);
     571           4 : }
     572             : 
     573       26643 : TEST(Run_WasmModule_Global_f64) {
     574           4 :   RunWasmModuleGlobalInitTest<double>(kWasmF64, -833.9);
     575           4 :   RunWasmModuleGlobalInitTest<double>(kWasmF64, 86374.25);
     576           4 : }
     577             : 
     578       26643 : TEST(InitDataAtTheUpperLimit) {
     579             :   {
     580             :     Isolate* isolate = CcTest::InitIsolateOnce();
     581             :     HandleScope scope(isolate);
     582           4 :     testing::SetupIsolateForWasmModule(isolate);
     583             : 
     584           4 :     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           4 :     };
     603             : 
     604             :     CompileAndInstantiateForTesting(
     605           4 :         isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
     606           4 :     if (thrower.error()) {
     607           0 :       thrower.Reify()->Print();
     608           0 :       FATAL("compile or instantiate error");
     609             :     }
     610             :   }
     611             :   Cleanup();
     612           4 : }
     613             : 
     614       26643 : TEST(EmptyMemoryNonEmptyDataSegment) {
     615             :   {
     616             :     Isolate* isolate = CcTest::InitIsolateOnce();
     617             :     HandleScope scope(isolate);
     618           4 :     testing::SetupIsolateForWasmModule(isolate);
     619             : 
     620           4 :     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           4 :     };
     639             : 
     640             :     CompileAndInstantiateForTesting(
     641           4 :         isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
     642             :     // It should not be possible to instantiate this module.
     643           4 :     CHECK(thrower.error());
     644             :   }
     645             :   Cleanup();
     646           4 : }
     647             : 
     648       26643 : TEST(EmptyMemoryEmptyDataSegment) {
     649             :   {
     650             :     Isolate* isolate = CcTest::InitIsolateOnce();
     651             :     HandleScope scope(isolate);
     652           4 :     testing::SetupIsolateForWasmModule(isolate);
     653             : 
     654           4 :     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           4 :     };
     672             : 
     673             :     CompileAndInstantiateForTesting(
     674           4 :         isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
     675             :     // It should be possible to instantiate this module.
     676           4 :     CHECK(!thrower.error());
     677             :   }
     678             :   Cleanup();
     679           4 : }
     680             : 
     681       26643 : TEST(MemoryWithOOBEmptyDataSegment) {
     682             :   {
     683             :     Isolate* isolate = CcTest::InitIsolateOnce();
     684             :     HandleScope scope(isolate);
     685           4 :     testing::SetupIsolateForWasmModule(isolate);
     686             : 
     687           4 :     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           4 :     };
     705             : 
     706             :     CompileAndInstantiateForTesting(
     707           4 :         isolate, &thrower, ModuleWireBytes(data, data + arraysize(data)));
     708             :     // It should not be possible to instantiate this module.
     709           4 :     CHECK(thrower.error());
     710             :   }
     711             :   Cleanup();
     712           4 : }
     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           8 :   ManuallyExternalizedBuffer(JSArrayBuffer buffer, Isolate* isolate)
     724             :       : isolate_(isolate),
     725             :         buffer_(buffer, isolate),
     726           8 :         allocation_base_(buffer->allocation_base()),
     727           8 :         allocation_length_(buffer->allocation_length()),
     728          16 :         should_free_(!isolate_->wasm_engine()->memory_tracker()->IsWasmMemory(
     729          32 :             buffer->backing_store())) {
     730          16 :     if (!isolate_->wasm_engine()->memory_tracker()->IsWasmMemory(
     731             :             buffer->backing_store())) {
     732           0 :       v8::Utils::ToLocal(buffer_)->Externalize();
     733             :     }
     734           8 :   }
     735           8 :   ~ManuallyExternalizedBuffer() {
     736           8 :     if (should_free_) {
     737           0 :       buffer_->FreeBackingStoreFromMainThread();
     738             :     }
     739             :   }
     740             : };
     741             : 
     742       26643 : TEST(Run_WasmModule_Buffer_Externalized_GrowMem) {
     743             :   {
     744             :     Isolate* isolate = CcTest::InitIsolateOnce();
     745             :     HandleScope scope(isolate);
     746           4 :     TestSignatures sigs;
     747           8 :     v8::internal::AccountingAllocator allocator;
     748           8 :     Zone zone(&allocator, ZONE_NAME);
     749             : 
     750           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     751           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     752             :     ExportAsMain(f);
     753             :     byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(6)), WASM_DROP,
     754           4 :                    WASM_MEMORY_SIZE};
     755           4 :     EMIT_CODE_WITH_END(f, code);
     756             : 
     757             :     ZoneBuffer buffer(&zone);
     758           4 :     builder->WriteTo(buffer);
     759           4 :     testing::SetupIsolateForWasmModule(isolate);
     760           4 :     ErrorThrower thrower(isolate, "Test");
     761             :     const Handle<WasmInstanceObject> instance =
     762           8 :         CompileAndInstantiateForTesting(
     763           4 :             isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()))
     764             :             .ToHandleChecked();
     765             :     Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate);
     766             : 
     767             :     // Fake the Embedder flow by externalizing the array buffer.
     768           4 :     ManuallyExternalizedBuffer buffer1(memory_object->array_buffer(), isolate);
     769             : 
     770             :     // Grow using the API.
     771           4 :     uint32_t result = WasmMemoryObject::Grow(isolate, memory_object, 4);
     772           4 :     CHECK_EQ(16, result);
     773           4 :     CHECK(buffer1.buffer_->was_detached());  // growing always detaches
     774           4 :     CHECK_EQ(0, buffer1.buffer_->byte_length());
     775             : 
     776           4 :     CHECK_NE(*buffer1.buffer_, memory_object->array_buffer());
     777             : 
     778             :     // Fake the Embedder flow by externalizing the array buffer.
     779           4 :     ManuallyExternalizedBuffer buffer2(memory_object->array_buffer(), isolate);
     780             : 
     781             :     // Grow using an internal WASM bytecode.
     782           4 :     result = testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
     783           4 :     CHECK_EQ(26, result);
     784           4 :     CHECK(buffer2.buffer_->was_detached());  // growing always detaches
     785           4 :     CHECK_EQ(0, buffer2.buffer_->byte_length());
     786           4 :     CHECK_NE(*buffer2.buffer_, memory_object->array_buffer());
     787             :   }
     788             :   Cleanup();
     789           4 : }
     790             : 
     791       26643 : TEST(Run_WasmModule_Buffer_Externalized_GrowMemMemSize) {
     792             :   {
     793             :     Isolate* isolate = CcTest::InitIsolateOnce();
     794             :     HandleScope scope(isolate);
     795             :     Handle<JSArrayBuffer> buffer;
     796           8 :     CHECK(wasm::NewArrayBuffer(isolate, 16 * kWasmPageSize).ToHandle(&buffer));
     797             :     Handle<WasmMemoryObject> mem_obj =
     798           4 :         WasmMemoryObject::New(isolate, buffer, 100);
     799           4 :     auto const contents = v8::Utils::ToLocal(buffer)->Externalize();
     800           4 :     int32_t result = WasmMemoryObject::Grow(isolate, mem_obj, 0);
     801           4 :     CHECK_EQ(16, result);
     802             :     constexpr bool is_wasm_memory = true;
     803             :     const JSArrayBuffer::Allocation allocation{contents.AllocationBase(),
     804             :                                                contents.AllocationLength(),
     805             :                                                contents.Data(), is_wasm_memory};
     806           4 :     JSArrayBuffer::FreeBackingStore(isolate, allocation);
     807             :   }
     808             :   Cleanup();
     809           4 : }
     810             : 
     811       26643 : TEST(Run_WasmModule_Buffer_Externalized_Detach) {
     812             :   {
     813             :     // Regression test for
     814             :     // https://bugs.chromium.org/p/chromium/issues/detail?id=731046
     815             :     Isolate* isolate = CcTest::InitIsolateOnce();
     816             :     HandleScope scope(isolate);
     817             :     Handle<JSArrayBuffer> buffer;
     818           8 :     CHECK(wasm::NewArrayBuffer(isolate, 16 * kWasmPageSize).ToHandle(&buffer));
     819           4 :     auto const contents = v8::Utils::ToLocal(buffer)->Externalize();
     820           4 :     wasm::DetachMemoryBuffer(isolate, buffer, true);
     821             :     constexpr bool is_wasm_memory = true;
     822             :     const JSArrayBuffer::Allocation allocation{contents.AllocationBase(),
     823             :                                                contents.AllocationLength(),
     824             :                                                contents.Data(), is_wasm_memory};
     825           4 :     JSArrayBuffer::FreeBackingStore(isolate, allocation);
     826             :   }
     827             :   Cleanup();
     828           4 : }
     829             : 
     830       26643 : TEST(Run_WasmModule_Buffer_Externalized_Regression_UseAfterFree) {
     831             :   // Regresion test for https://crbug.com/813876
     832             :   Isolate* isolate = CcTest::InitIsolateOnce();
     833             :   HandleScope scope(isolate);
     834             :   Handle<JSArrayBuffer> buffer;
     835           8 :   CHECK(wasm::NewArrayBuffer(isolate, 16 * kWasmPageSize).ToHandle(&buffer));
     836           4 :   Handle<WasmMemoryObject> mem = WasmMemoryObject::New(isolate, buffer, 128);
     837           4 :   auto contents = v8::Utils::ToLocal(buffer)->Externalize();
     838           4 :   WasmMemoryObject::Grow(isolate, mem, 0);
     839             :   constexpr bool is_wasm_memory = true;
     840           4 :   JSArrayBuffer::FreeBackingStore(
     841             :       isolate, JSArrayBuffer::Allocation(contents.AllocationBase(),
     842             :                                          contents.AllocationLength(),
     843           4 :                                          contents.Data(), is_wasm_memory));
     844             :   // Make sure we can write to the buffer without crashing
     845             :   uint32_t* int_buffer =
     846             :       reinterpret_cast<uint32_t*>(mem->array_buffer()->backing_store());
     847           4 :   int_buffer[0] = 0;
     848           4 : }
     849             : 
     850             : #if V8_TARGET_ARCH_64_BIT
     851       26643 : TEST(Run_WasmModule_Reclaim_Memory) {
     852             :   // Make sure we can allocate memories without running out of address space.
     853             :   Isolate* isolate = CcTest::InitIsolateOnce();
     854             :   Handle<JSArrayBuffer> buffer;
     855        2052 :   for (int i = 0; i < 256; ++i) {
     856             :     HandleScope scope(isolate);
     857        2048 :     CHECK(NewArrayBuffer(isolate, kWasmPageSize).ToHandle(&buffer));
     858             :   }
     859           4 : }
     860             : #endif
     861             : 
     862       26643 : TEST(AtomicOpDisassembly) {
     863             :   {
     864             :     EXPERIMENTAL_FLAG_SCOPE(threads);
     865           4 :     TestSignatures sigs;
     866             :     Isolate* isolate = CcTest::InitIsolateOnce();
     867           8 :     v8::internal::AccountingAllocator allocator;
     868           8 :     Zone zone(&allocator, ZONE_NAME);
     869             : 
     870           4 :     WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
     871           4 :     builder->SetHasSharedMemory();
     872           4 :     builder->SetMaxMemorySize(16);
     873           4 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
     874             :     ExportAsMain(f);
     875             :     byte code[] = {
     876             :         WASM_ATOMICS_STORE_OP(kExprI32AtomicStore, WASM_ZERO, WASM_GET_LOCAL(0),
     877             :                               MachineRepresentation::kWord32),
     878             :         WASM_ATOMICS_LOAD_OP(kExprI32AtomicLoad, WASM_ZERO,
     879           4 :                              MachineRepresentation::kWord32)};
     880           4 :     EMIT_CODE_WITH_END(f, code);
     881             : 
     882             :     HandleScope scope(isolate);
     883             :     ZoneBuffer buffer(&zone);
     884           4 :     builder->WriteTo(buffer);
     885           4 :     testing::SetupIsolateForWasmModule(isolate);
     886             : 
     887           4 :     ErrorThrower thrower(isolate, "Test");
     888           4 :     auto enabled_features = WasmFeaturesFromIsolate(isolate);
     889             :     MaybeHandle<WasmModuleObject> module_object =
     890             :         isolate->wasm_engine()->SyncCompile(
     891             :             isolate, enabled_features, &thrower,
     892           4 :             ModuleWireBytes(buffer.begin(), buffer.end()));
     893             : 
     894           4 :     module_object.ToHandleChecked()->DisassembleFunction(0);
     895             :   }
     896             :   Cleanup();
     897           4 : }
     898             : 
     899             : #undef EMIT_CODE_WITH_END
     900             : 
     901             : }  // namespace test_run_wasm_module
     902             : }  // namespace wasm
     903             : }  // namespace internal
     904       79917 : }  // namespace v8

Generated by: LCOV version 1.10