LCOV - code coverage report
Current view: top level - test/cctest - test-icache.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 56 56 100.0 %
Date: 2019-01-20 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          75 : static void FloodWithInc(Isolate* isolate, TestingAssemblerBuffer* buffer) {
      25         225 :   MacroAssembler masm(isolate, CodeObjectRequired::kYes, buffer->CreateView());
      26             : #if V8_TARGET_ARCH_IA32
      27             :   __ mov(eax, Operand(esp, kPointerSize));
      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        7575 :   for (int i = 0; i < kNumInstr; ++i) {
      34        7500 :     __ 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             :   __ function_descriptor();
      56             :   for (int i = 0; i < kNumInstr; ++i) {
      57             :     __ addi(r3, r3, Operand(1));
      58             :   }
      59             : #elif V8_TARGET_ARCH_S390
      60             :   for (int i = 0; i < kNumInstr; ++i) {
      61             :     __ agfi(r2, Operand(1));
      62             :   }
      63             : #else
      64             : #error Unsupported architecture
      65             : #endif
      66          75 :   __ Ret();
      67          75 :   CodeDesc desc;
      68          75 :   masm.GetCode(isolate, &desc);
      69          75 : }
      70             : 
      71          75 : static void FloodWithNop(Isolate* isolate, TestingAssemblerBuffer* buffer) {
      72         225 :   MacroAssembler masm(isolate, CodeObjectRequired::kYes, buffer->CreateView());
      73             : #if V8_TARGET_ARCH_IA32
      74             :   __ mov(eax, Operand(esp, kPointerSize));
      75             : #elif V8_TARGET_ARCH_X64
      76             :   __ movl(rax, arg_reg_1);
      77             : #elif V8_TARGET_ARCH_MIPS
      78             :   __ mov(v0, a0);
      79             : #elif V8_TARGET_ARCH_MIPS64
      80             :   __ mov(v0, a0);
      81             : #elif V8_TARGET_ARCH_PPC
      82             :   __ function_descriptor();
      83             : #endif
      84        7575 :   for (int i = 0; i < kNumInstr; ++i) {
      85        7500 :     __ nop();
      86             :   }
      87          75 :   __ Ret();
      88          75 :   CodeDesc desc;
      89          75 :   masm.GetCode(isolate, &desc);
      90          75 : }
      91             : 
      92             : // Order of operation for this test case:
      93             : //   exec -> perm(RW) -> patch -> flush -> perm(RX) -> exec
      94       28342 : TEST(TestFlushICacheOfWritable) {
      95             :   Isolate* isolate = CcTest::i_isolate();
      96             :   HandleScope handles(isolate);
      97             : 
      98          30 :   for (int i = 0; i < kNumIterations; ++i) {
      99             :     auto buffer = AllocateAssemblerBuffer(kBufferSize);
     100             : 
     101             :     // Allow calling the function from C++.
     102          25 :     auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
     103             : 
     104          50 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     105             :                          buffer->size(), v8::PageAllocator::kReadWrite));
     106          25 :     FloodWithInc(isolate, buffer.get());
     107          50 :     Assembler::FlushICache(buffer->start(), buffer->size());
     108          50 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     109             :                          buffer->size(), v8::PageAllocator::kReadExecute));
     110          25 :     CHECK_EQ(23 + kNumInstr, f.Call(23));  // Call into generated code.
     111          50 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     112             :                          buffer->size(), v8::PageAllocator::kReadWrite));
     113          25 :     FloodWithNop(isolate, buffer.get());
     114          50 :     Assembler::FlushICache(buffer->start(), buffer->size());
     115          50 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     116             :                          buffer->size(), v8::PageAllocator::kReadExecute));
     117          25 :     CHECK_EQ(23, f.Call(23));  // Call into generated code.
     118             :   }
     119           5 : }
     120             : 
     121             : #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64
     122             : // Note that this order of operations is not supported on ARM32/64 because on
     123             : // some older ARM32/64 kernels there is a bug which causes an access error on
     124             : // cache flush instructions to trigger access error on non-writable memory.
     125             : // See https://bugs.chromium.org/p/v8/issues/detail?id=8157
     126             : //
     127             : // Also note that this requires {kBufferSize == 8 * KB} to reproduce.
     128             : //
     129             : // The order of operations in V8 is akin to {TestFlushICacheOfWritable} above.
     130             : // It is hence OK to disable the below test on some architectures. Only the
     131             : // above test case should remain enabled on all architectures.
     132             : #define CONDITIONAL_TEST DISABLED_TEST
     133             : #else
     134             : #define CONDITIONAL_TEST TEST
     135             : #endif
     136             : 
     137             : // Order of operation for this test case:
     138             : //   exec -> perm(RW) -> patch -> perm(RX) -> flush -> exec
     139       28342 : CONDITIONAL_TEST(TestFlushICacheOfExecutable) {
     140             :   Isolate* isolate = CcTest::i_isolate();
     141             :   HandleScope handles(isolate);
     142             : 
     143          30 :   for (int i = 0; i < kNumIterations; ++i) {
     144             :     auto buffer = AllocateAssemblerBuffer(kBufferSize);
     145             : 
     146             :     // Allow calling the function from C++.
     147          25 :     auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
     148             : 
     149          50 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     150             :                          buffer->size(), v8::PageAllocator::kReadWrite));
     151          25 :     FloodWithInc(isolate, buffer.get());
     152          50 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     153             :                          buffer->size(), v8::PageAllocator::kReadExecute));
     154          50 :     Assembler::FlushICache(buffer->start(), buffer->size());
     155          25 :     CHECK_EQ(23 + kNumInstr, f.Call(23));  // Call into generated code.
     156          50 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     157             :                          buffer->size(), v8::PageAllocator::kReadWrite));
     158          25 :     FloodWithNop(isolate, buffer.get());
     159          50 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     160             :                          buffer->size(), v8::PageAllocator::kReadExecute));
     161          50 :     Assembler::FlushICache(buffer->start(), buffer->size());
     162          25 :     CHECK_EQ(23, f.Call(23));  // Call into generated code.
     163             :   }
     164           5 : }
     165             : 
     166             : #undef CONDITIONAL_TEST
     167             : 
     168             : // Order of operation for this test case:
     169             : //   perm(RWX) -> exec -> patch -> flush -> exec
     170       28342 : TEST(TestFlushICacheOfWritableAndExecutable) {
     171             :   Isolate* isolate = CcTest::i_isolate();
     172             :   HandleScope handles(isolate);
     173             : 
     174          30 :   for (int i = 0; i < kNumIterations; ++i) {
     175             :     auto buffer = AllocateAssemblerBuffer(kBufferSize);
     176             : 
     177             :     // Allow calling the function from C++.
     178          25 :     auto f = GeneratedCode<F0>::FromBuffer(isolate, buffer->start());
     179             : 
     180          50 :     CHECK(SetPermissions(GetPlatformPageAllocator(), buffer->start(),
     181             :                          buffer->size(), v8::PageAllocator::kReadWriteExecute));
     182          25 :     FloodWithInc(isolate, buffer.get());
     183          50 :     Assembler::FlushICache(buffer->start(), buffer->size());
     184          25 :     CHECK_EQ(23 + kNumInstr, f.Call(23));  // Call into generated code.
     185          25 :     FloodWithNop(isolate, buffer.get());
     186          50 :     Assembler::FlushICache(buffer->start(), buffer->size());
     187          25 :     CHECK_EQ(23, f.Call(23));  // Call into generated code.
     188             :   }
     189           5 : }
     190             : 
     191             : #undef __
     192             : 
     193             : }  // namespace test_icache
     194             : }  // namespace internal
     195       85011 : }  // namespace v8

Generated by: LCOV version 1.10