Home | History | Annotate | Download | only in cctest
      1 // Copyright 2009 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include <stdlib.h>
     29 
     30 #include "v8.h"
     31 
     32 #include "macro-assembler.h"
     33 #include "factory.h"
     34 #include "platform.h"
     35 #include "serialize.h"
     36 #include "cctest.h"
     37 
     38 using v8::internal::Assembler;
     39 using v8::internal::CodeDesc;
     40 using v8::internal::FUNCTION_CAST;
     41 using v8::internal::Immediate;
     42 using v8::internal::Isolate;
     43 using v8::internal::Label;
     44 using v8::internal::OS;
     45 using v8::internal::Operand;
     46 using v8::internal::byte;
     47 using v8::internal::greater;
     48 using v8::internal::less_equal;
     49 using v8::internal::not_equal;
     50 using v8::internal::r13;
     51 using v8::internal::r15;
     52 using v8::internal::r8;
     53 using v8::internal::r9;
     54 using v8::internal::rax;
     55 using v8::internal::rbp;
     56 using v8::internal::rcx;
     57 using v8::internal::rdi;
     58 using v8::internal::rdx;
     59 using v8::internal::rsi;
     60 using v8::internal::rsp;
     61 using v8::internal::times_1;
     62 
     63 // Test the x64 assembler by compiling some simple functions into
     64 // a buffer and executing them.  These tests do not initialize the
     65 // V8 library, create a context, or use any V8 objects.
     66 // The AMD64 calling convention is used, with the first six arguments
     67 // in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in
     68 // the XMM registers.  The return value is in RAX.
     69 // This calling convention is used on Linux, with GCC, and on Mac OS,
     70 // with GCC.  A different convention is used on 64-bit windows,
     71 // where the first four integer arguments are passed in RCX, RDX, R8 and R9.
     72 
     73 typedef int (*F0)();
     74 typedef int (*F1)(int64_t x);
     75 typedef int (*F2)(int64_t x, int64_t y);
     76 
     77 #ifdef _WIN64
     78 static const v8::internal::Register arg1 = rcx;
     79 static const v8::internal::Register arg2 = rdx;
     80 #else
     81 static const v8::internal::Register arg1 = rdi;
     82 static const v8::internal::Register arg2 = rsi;
     83 #endif
     84 
     85 #define __ assm.
     86 
     87 
     88 TEST(AssemblerX64ReturnOperation) {
     89   OS::Setup();
     90   // Allocate an executable page of memory.
     91   size_t actual_size;
     92   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
     93                                                  &actual_size,
     94                                                  true));
     95   CHECK(buffer);
     96   Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
     97 
     98   // Assemble a simple function that copies argument 2 and returns it.
     99   __ movq(rax, arg2);
    100   __ nop();
    101   __ ret(0);
    102 
    103   CodeDesc desc;
    104   assm.GetCode(&desc);
    105   // Call the function from C++.
    106   int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
    107   CHECK_EQ(2, result);
    108 }
    109 
    110 TEST(AssemblerX64StackOperations) {
    111   OS::Setup();
    112   // Allocate an executable page of memory.
    113   size_t actual_size;
    114   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
    115                                                  &actual_size,
    116                                                  true));
    117   CHECK(buffer);
    118   Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
    119 
    120   // Assemble a simple function that copies argument 2 and returns it.
    121   // We compile without stack frame pointers, so the gdb debugger shows
    122   // incorrect stack frames when debugging this function (which has them).
    123   __ push(rbp);
    124   __ movq(rbp, rsp);
    125   __ push(arg2);  // Value at (rbp - 8)
    126   __ push(arg2);  // Value at (rbp - 16)
    127   __ push(arg1);  // Value at (rbp - 24)
    128   __ pop(rax);
    129   __ pop(rax);
    130   __ pop(rax);
    131   __ pop(rbp);
    132   __ nop();
    133   __ ret(0);
    134 
    135   CodeDesc desc;
    136   assm.GetCode(&desc);
    137   // Call the function from C++.
    138   int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
    139   CHECK_EQ(2, result);
    140 }
    141 
    142 TEST(AssemblerX64ArithmeticOperations) {
    143   OS::Setup();
    144   // Allocate an executable page of memory.
    145   size_t actual_size;
    146   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
    147                                                  &actual_size,
    148                                                  true));
    149   CHECK(buffer);
    150   Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
    151 
    152   // Assemble a simple function that adds arguments returning the sum.
    153   __ movq(rax, arg2);
    154   __ addq(rax, arg1);
    155   __ ret(0);
    156 
    157   CodeDesc desc;
    158   assm.GetCode(&desc);
    159   // Call the function from C++.
    160   int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
    161   CHECK_EQ(5, result);
    162 }
    163 
    164 TEST(AssemblerX64ImulOperation) {
    165   OS::Setup();
    166   // Allocate an executable page of memory.
    167   size_t actual_size;
    168   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
    169                                                  &actual_size,
    170                                                  true));
    171   CHECK(buffer);
    172   Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
    173 
    174   // Assemble a simple function that multiplies arguments returning the high
    175   // word.
    176   __ movq(rax, arg2);
    177   __ imul(arg1);
    178   __ movq(rax, rdx);
    179   __ ret(0);
    180 
    181   CodeDesc desc;
    182   assm.GetCode(&desc);
    183   // Call the function from C++.
    184   int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
    185   CHECK_EQ(0, result);
    186   result =  FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l);
    187   CHECK_EQ(1, result);
    188   result =  FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l);
    189   CHECK_EQ(-1, result);
    190 }
    191 
    192 TEST(AssemblerX64MemoryOperands) {
    193   OS::Setup();
    194   // Allocate an executable page of memory.
    195   size_t actual_size;
    196   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
    197                                                  &actual_size,
    198                                                  true));
    199   CHECK(buffer);
    200   Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
    201 
    202   // Assemble a simple function that copies argument 2 and returns it.
    203   __ push(rbp);
    204   __ movq(rbp, rsp);
    205 
    206   __ push(arg2);  // Value at (rbp - 8)
    207   __ push(arg2);  // Value at (rbp - 16)
    208   __ push(arg1);  // Value at (rbp - 24)
    209 
    210   const int kStackElementSize = 8;
    211   __ movq(rax, Operand(rbp, -3 * kStackElementSize));
    212   __ pop(arg2);
    213   __ pop(arg2);
    214   __ pop(arg2);
    215   __ pop(rbp);
    216   __ nop();
    217   __ ret(0);
    218 
    219   CodeDesc desc;
    220   assm.GetCode(&desc);
    221   // Call the function from C++.
    222   int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
    223   CHECK_EQ(3, result);
    224 }
    225 
    226 TEST(AssemblerX64ControlFlow) {
    227   OS::Setup();
    228   // Allocate an executable page of memory.
    229   size_t actual_size;
    230   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
    231                                                  &actual_size,
    232                                                  true));
    233   CHECK(buffer);
    234   Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
    235 
    236   // Assemble a simple function that copies argument 1 and returns it.
    237   __ push(rbp);
    238 
    239   __ movq(rbp, rsp);
    240   __ movq(rax, arg1);
    241   Label target;
    242   __ jmp(&target);
    243   __ movq(rax, arg2);
    244   __ bind(&target);
    245   __ pop(rbp);
    246   __ ret(0);
    247 
    248   CodeDesc desc;
    249   assm.GetCode(&desc);
    250   // Call the function from C++.
    251   int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
    252   CHECK_EQ(3, result);
    253 }
    254 
    255 TEST(AssemblerX64LoopImmediates) {
    256   OS::Setup();
    257   // Allocate an executable page of memory.
    258   size_t actual_size;
    259   byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
    260                                                  &actual_size,
    261                                                  true));
    262   CHECK(buffer);
    263   Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size));
    264   // Assemble two loops using rax as counter, and verify the ending counts.
    265   Label Fail;
    266   __ movq(rax, Immediate(-3));
    267   Label Loop1_test;
    268   Label Loop1_body;
    269   __ jmp(&Loop1_test);
    270   __ bind(&Loop1_body);
    271   __ addq(rax, Immediate(7));
    272   __ bind(&Loop1_test);
    273   __ cmpq(rax, Immediate(20));
    274   __ j(less_equal, &Loop1_body);
    275   // Did the loop terminate with the expected value?
    276   __ cmpq(rax, Immediate(25));
    277   __ j(not_equal, &Fail);
    278 
    279   Label Loop2_test;
    280   Label Loop2_body;
    281   __ movq(rax, Immediate(0x11FEED00));
    282   __ jmp(&Loop2_test);
    283   __ bind(&Loop2_body);
    284   __ addq(rax, Immediate(-0x1100));
    285   __ bind(&Loop2_test);
    286   __ cmpq(rax, Immediate(0x11FE8000));
    287   __ j(greater, &Loop2_body);
    288   // Did the loop terminate with the expected value?
    289   __ cmpq(rax, Immediate(0x11FE7600));
    290   __ j(not_equal, &Fail);
    291 
    292   __ movq(rax, Immediate(1));
    293   __ ret(0);
    294   __ bind(&Fail);
    295   __ movq(rax, Immediate(0));
    296   __ ret(0);
    297 
    298   CodeDesc desc;
    299   assm.GetCode(&desc);
    300   // Call the function from C++.
    301   int result =  FUNCTION_CAST<F0>(buffer)();
    302   CHECK_EQ(1, result);
    303 }
    304 
    305 
    306 TEST(OperandRegisterDependency) {
    307   int offsets[4] = {0, 1, 0xfed, 0xbeefcad};
    308   for (int i = 0; i < 4; i++) {
    309     int offset = offsets[i];
    310     CHECK(Operand(rax, offset).AddressUsesRegister(rax));
    311     CHECK(!Operand(rax, offset).AddressUsesRegister(r8));
    312     CHECK(!Operand(rax, offset).AddressUsesRegister(rcx));
    313 
    314     CHECK(Operand(rax, rax, times_1, offset).AddressUsesRegister(rax));
    315     CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(r8));
    316     CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(rcx));
    317 
    318     CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rax));
    319     CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rcx));
    320     CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r8));
    321     CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r9));
    322     CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rdx));
    323     CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rsp));
    324 
    325     CHECK(Operand(rsp, offset).AddressUsesRegister(rsp));
    326     CHECK(!Operand(rsp, offset).AddressUsesRegister(rax));
    327     CHECK(!Operand(rsp, offset).AddressUsesRegister(r15));
    328 
    329     CHECK(Operand(rbp, offset).AddressUsesRegister(rbp));
    330     CHECK(!Operand(rbp, offset).AddressUsesRegister(rax));
    331     CHECK(!Operand(rbp, offset).AddressUsesRegister(r13));
    332 
    333     CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rbp));
    334     CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rax));
    335     CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rcx));
    336     CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r13));
    337     CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r8));
    338     CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rsp));
    339 
    340     CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp));
    341     CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp));
    342     CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax));
    343     CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r15));
    344     CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13));
    345   }
    346 }
    347 
    348 #undef __
    349