LCOV - code coverage report
Current view: top level - test/cctest - test-icache.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 53 53 100.0 %
Date: 2019-04-17 Functions: 7 7 100.0 %

          Line data    Source code
       1             : // Copyright 2018 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 "src/assembler-inl.h"
       6             : #include "src/handles-inl.h"
       7             : #include "src/macro-assembler-inl.h"
       8             : #include "src/simulator.h"
       9             : #include "test/cctest/cctest.h"
      10             : #include "test/common/assembler-tester.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : namespace test_icache {
      15             : 
      16             : using F0 = int(int);
      17             : 
      18             : #define __ masm.
      19             : 
      20             : static constexpr int kNumInstr = 100;
      21             : static constexpr int kNumIterations = 5;
      22             : static constexpr int kBufferSize = 8 * KB;
      23             : 
      24          60 : static void FloodWithInc(Isolate* isolate, TestingAssemblerBuffer* buffer) {
      25         120 :   MacroAssembler masm(isolate, CodeObjectRequired::kYes, buffer->CreateView());
      26             : #if V8_TARGET_ARCH_IA32
      27             :   __ mov(eax, Operand(esp, kSystemPointerSize));
      28             :   for (int i = 0; i < kNumInstr; ++i) {
      29             :     __ add(eax, Immediate(1));
      30             :   }
      31             : #elif V8_TARGET_ARCH_X64
      32             :   __ movl(rax, arg_reg_1);
      33       12060 :   for (int i = 0; i < kNumInstr; ++i) {
      34             :     __ addl(rax, Immediate(1));
      35             :   }
      36             : #elif V8_TARGET_ARCH_ARM64
      37             :   for (int i = 0; i < kNumInstr; ++i) {
      38             :     __ Add(x0, x0, Operand(1));
      39             :   }
      40             : #elif V8_TARGET_ARCH_ARM
      41             :   for (int i = 0; i < kNumInstr; ++i) {
      42             :     __ add(r0, r0, Operand(1));
      43             :   }
      44             : #elif V8_TARGET_ARCH_MIPS
      45             :   __ mov(v0, a0);
      46             :   for (int i = 0; i < kNumInstr; ++i) {
      47             :     __ Addu(v0, v0, Operand(1));
      48             :   }
      49             : #elif V8_TARGET_ARCH_MIPS64
      50             :   __ mov(v0, a0);
      51             :   for (int i = 0; i < kNumInstr; ++i) {
      52             :     __ Addu(v0, v0, Operand(1));
      53             :   }
      54             : #elif V8_TARGET_ARCH_PPC
      55             :   for (int i = 0; i < kNumInstr; ++i) {
      56             :     __ addi(r3, r3, Operand(1));
      57             :   }
      58             : #elif V8_TARGET_ARCH_S390
      59             :   for (int i = 0; i < kNumInstr; ++i) {
      60             :     __ agfi(r2, Operand(1));
      61             :   }
      62             : #else
      63             : #error Unsupported architecture
      64             : #endif
      65          60 :   __ Ret();
      66          60 :   CodeDesc desc;
      67             :   masm.GetCode(isolate, &desc);
      68          60 : }
      69             : 
      70          60 : static void FloodWithNop(Isolate* isolate, TestingAssemblerBuffer* buffer) {
      71         120 :   MacroAssembler masm(isolate, CodeObjectRequired::kYes, buffer->CreateView());
      72             : #if V8_TARGET_ARCH_IA32
      73             :   __ mov(eax, Operand(esp, kSystemPointerSize));
      74             : #elif V8_TARGET_ARCH_X64
      75             :   __ movl(rax, arg_reg_1);
      76             : #elif V8_TARGET_ARCH_MIPS
      77             :   __ mov(v0, a0);
      78             : #elif V8_TARGET_ARCH_MIPS64
      79             :   __ mov(v0, a0);
      80             : #endif
      81       12060 :   for (int i = 0; i < kNumInstr; ++i) {
      82        6000 :     __ nop();
      83             :   }
      84          60 :   __ Ret();
      85          60 :   CodeDesc desc;
      86             :   masm.GetCode(isolate, &desc);
      87          60 : }
      88             : 
      89             : // Order of operation for this test case:
      90             : //   exec -> perm(RW) -> patch -> flush -> perm(RX) -> exec
      91       26643 : TEST(TestFlushICacheOfWritable) {
      92             :   Isolate* isolate = CcTest::i_isolate();
      93             :   HandleScope handles(isolate);
      94             : 
      95          44 :   for (int i = 0; i < kNumIterations; ++i) {
      96             :     auto buffer = AllocateAssemblerBuffer(kBufferSize);
      97             : 
      98             :     // Allow calling the function from C++.
      99          20 :     auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
     100             : 
     101          40 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     102             :                          buffer->size(), v8::PageAllocator::kReadWrite));
     103          20 :     FloodWithInc(isolate, buffer.get());
     104          40 :     FlushInstructionCache(buffer->start(), buffer->size());
     105          40 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     106             :                          buffer->size(), v8::PageAllocator::kReadExecute));
     107          20 :     CHECK_EQ(23 + kNumInstr, f.Call(23));  // Call into generated code.
     108          40 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     109             :                          buffer->size(), v8::PageAllocator::kReadWrite));
     110          20 :     FloodWithNop(isolate, buffer.get());
     111          40 :     FlushInstructionCache(buffer->start(), buffer->size());
     112          40 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     113             :                          buffer->size(), v8::PageAllocator::kReadExecute));
     114          20 :     CHECK_EQ(23, f.Call(23));  // Call into generated code.
     115             :   }
     116           4 : }
     117             : 
     118             : #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64
     119             : // Note that this order of operations is not supported on ARM32/64 because on
     120             : // some older ARM32/64 kernels there is a bug which causes an access error on
     121             : // cache flush instructions to trigger access error on non-writable memory.
     122             : // See https://bugs.chromium.org/p/v8/issues/detail?id=8157
     123             : //
     124             : // Also note that this requires {kBufferSize == 8 * KB} to reproduce.
     125             : //
     126             : // The order of operations in V8 is akin to {TestFlushICacheOfWritable} above.
     127             : // It is hence OK to disable the below test on some architectures. Only the
     128             : // above test case should remain enabled on all architectures.
     129             : #define CONDITIONAL_TEST DISABLED_TEST
     130             : #else
     131             : #define CONDITIONAL_TEST TEST
     132             : #endif
     133             : 
     134             : // Order of operation for this test case:
     135             : //   exec -> perm(RW) -> patch -> perm(RX) -> flush -> exec
     136       26643 : CONDITIONAL_TEST(TestFlushICacheOfExecutable) {
     137             :   Isolate* isolate = CcTest::i_isolate();
     138             :   HandleScope handles(isolate);
     139             : 
     140          44 :   for (int i = 0; i < kNumIterations; ++i) {
     141             :     auto buffer = AllocateAssemblerBuffer(kBufferSize);
     142             : 
     143             :     // Allow calling the function from C++.
     144          20 :     auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
     145             : 
     146          40 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     147             :                          buffer->size(), v8::PageAllocator::kReadWrite));
     148          20 :     FloodWithInc(isolate, buffer.get());
     149          40 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     150             :                          buffer->size(), v8::PageAllocator::kReadExecute));
     151          40 :     FlushInstructionCache(buffer->start(), buffer->size());
     152          20 :     CHECK_EQ(23 + kNumInstr, f.Call(23));  // Call into generated code.
     153          40 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     154             :                          buffer->size(), v8::PageAllocator::kReadWrite));
     155          20 :     FloodWithNop(isolate, buffer.get());
     156          40 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     157             :                          buffer->size(), v8::PageAllocator::kReadExecute));
     158          40 :     FlushInstructionCache(buffer->start(), buffer->size());
     159          20 :     CHECK_EQ(23, f.Call(23));  // Call into generated code.
     160             :   }
     161           4 : }
     162             : 
     163             : #undef CONDITIONAL_TEST
     164             : 
     165             : // Order of operation for this test case:
     166             : //   perm(RWX) -> exec -> patch -> flush -> exec
     167       26643 : TEST(TestFlushICacheOfWritableAndExecutable) {
     168             :   Isolate* isolate = CcTest::i_isolate();
     169             :   HandleScope handles(isolate);
     170             : 
     171          44 :   for (int i = 0; i < kNumIterations; ++i) {
     172             :     auto buffer = AllocateAssemblerBuffer(kBufferSize);
     173             : 
     174             :     // Allow calling the function from C++.
     175          20 :     auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
     176             : 
     177          40 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     178             :                          buffer->size(), v8::PageAllocator::kReadWriteExecute));
     179          20 :     FloodWithInc(isolate, buffer.get());
     180          40 :     FlushInstructionCache(buffer->start(), buffer->size());
     181          20 :     CHECK_EQ(23 + kNumInstr, f.Call(23));  // Call into generated code.
     182          20 :     FloodWithNop(isolate, buffer.get());
     183          40 :     FlushInstructionCache(buffer->start(), buffer->size());
     184          20 :     CHECK_EQ(23, f.Call(23));  // Call into generated code.
     185             :   }
     186           4 : }
     187             : 
     188             : #undef __
     189             : 
     190             : }  // namespace test_icache
     191             : }  // namespace internal
     192       79917 : }  // namespace v8

Generated by: LCOV version 1.10