Home | History | Annotate | Download | only in cctest
      1 // Copyright 2011 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 "disassembler.h"
     33 #include "factory.h"
     34 #include "macro-assembler.h"
     35 #include "platform.h"
     36 #include "serialize.h"
     37 #include "cctest.h"
     38 
     39 using namespace v8::internal;
     40 
     41 
     42 typedef int (*F0)();
     43 typedef int (*F1)(int x);
     44 typedef int (*F2)(int x, int y);
     45 
     46 
     47 static v8::Persistent<v8::Context> env;
     48 
     49 
     50 static void InitializeVM() {
     51   if (env.IsEmpty()) {
     52     env = v8::Context::New();
     53   }
     54 }
     55 
     56 
     57 #define __ assm.
     58 
     59 TEST(AssemblerIa320) {
     60   InitializeVM();
     61   v8::HandleScope scope;
     62 
     63   v8::internal::byte buffer[256];
     64   Assembler assm(Isolate::Current(), buffer, sizeof buffer);
     65 
     66   __ mov(eax, Operand(esp, 4));
     67   __ add(eax, Operand(esp, 8));
     68   __ ret(0);
     69 
     70   CodeDesc desc;
     71   assm.GetCode(&desc);
     72   Object* code = HEAP->CreateCode(
     73       desc,
     74       Code::ComputeFlags(Code::STUB),
     75       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
     76   CHECK(code->IsCode());
     77 #ifdef OBJECT_PRINT
     78   Code::cast(code)->Print();
     79 #endif
     80   F2 f = FUNCTION_CAST<F2>(Code::cast(code)->entry());
     81   int res = f(3, 4);
     82   ::printf("f() = %d\n", res);
     83   CHECK_EQ(7, res);
     84 }
     85 
     86 
     87 TEST(AssemblerIa321) {
     88   InitializeVM();
     89   v8::HandleScope scope;
     90 
     91   v8::internal::byte buffer[256];
     92   Assembler assm(Isolate::Current(), buffer, sizeof buffer);
     93   Label L, C;
     94 
     95   __ mov(edx, Operand(esp, 4));
     96   __ xor_(eax, eax);  // clear eax
     97   __ jmp(&C);
     98 
     99   __ bind(&L);
    100   __ add(eax, edx);
    101   __ sub(edx, Immediate(1));
    102 
    103   __ bind(&C);
    104   __ test(edx, edx);
    105   __ j(not_zero, &L);
    106   __ ret(0);
    107 
    108   CodeDesc desc;
    109   assm.GetCode(&desc);
    110   Object* code = HEAP->CreateCode(
    111       desc,
    112       Code::ComputeFlags(Code::STUB),
    113       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
    114   CHECK(code->IsCode());
    115 #ifdef OBJECT_PRINT
    116   Code::cast(code)->Print();
    117 #endif
    118   F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
    119   int res = f(100);
    120   ::printf("f() = %d\n", res);
    121   CHECK_EQ(5050, res);
    122 }
    123 
    124 
    125 TEST(AssemblerIa322) {
    126   InitializeVM();
    127   v8::HandleScope scope;
    128 
    129   v8::internal::byte buffer[256];
    130   Assembler assm(Isolate::Current(), buffer, sizeof buffer);
    131   Label L, C;
    132 
    133   __ mov(edx, Operand(esp, 4));
    134   __ mov(eax, 1);
    135   __ jmp(&C);
    136 
    137   __ bind(&L);
    138   __ imul(eax, edx);
    139   __ sub(edx, Immediate(1));
    140 
    141   __ bind(&C);
    142   __ test(edx, edx);
    143   __ j(not_zero, &L);
    144   __ ret(0);
    145 
    146   // some relocated stuff here, not executed
    147   __ mov(eax, FACTORY->true_value());
    148   __ jmp(NULL, RelocInfo::RUNTIME_ENTRY);
    149 
    150   CodeDesc desc;
    151   assm.GetCode(&desc);
    152   Object* code = HEAP->CreateCode(
    153       desc,
    154       Code::ComputeFlags(Code::STUB),
    155       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
    156   CHECK(code->IsCode());
    157 #ifdef OBJECT_PRINT
    158   Code::cast(code)->Print();
    159 #endif
    160   F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
    161   int res = f(10);
    162   ::printf("f() = %d\n", res);
    163   CHECK_EQ(3628800, res);
    164 }
    165 
    166 
    167 typedef int (*F3)(float x);
    168 
    169 TEST(AssemblerIa323) {
    170   InitializeVM();
    171   if (!CpuFeatures::IsSupported(SSE2)) return;
    172 
    173   v8::HandleScope scope;
    174 
    175   v8::internal::byte buffer[256];
    176   Assembler assm(Isolate::Current(), buffer, sizeof buffer);
    177 
    178   CHECK(CpuFeatures::IsSupported(SSE2));
    179   { CpuFeatures::Scope fscope(SSE2);
    180     __ cvttss2si(eax, Operand(esp, 4));
    181     __ ret(0);
    182   }
    183 
    184   CodeDesc desc;
    185   assm.GetCode(&desc);
    186   Code* code = Code::cast(HEAP->CreateCode(
    187       desc,
    188       Code::ComputeFlags(Code::STUB),
    189       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
    190   // don't print the code - our disassembler can't handle cvttss2si
    191   // instead print bytes
    192   Disassembler::Dump(stdout,
    193                      code->instruction_start(),
    194                      code->instruction_start() + code->instruction_size());
    195   F3 f = FUNCTION_CAST<F3>(code->entry());
    196   int res = f(static_cast<float>(-3.1415));
    197   ::printf("f() = %d\n", res);
    198   CHECK_EQ(-3, res);
    199 }
    200 
    201 
    202 typedef int (*F4)(double x);
    203 
    204 TEST(AssemblerIa324) {
    205   InitializeVM();
    206   if (!CpuFeatures::IsSupported(SSE2)) return;
    207 
    208   v8::HandleScope scope;
    209 
    210   v8::internal::byte buffer[256];
    211   Assembler assm(Isolate::Current(), buffer, sizeof buffer);
    212 
    213   CHECK(CpuFeatures::IsSupported(SSE2));
    214   CpuFeatures::Scope fscope(SSE2);
    215   __ cvttsd2si(eax, Operand(esp, 4));
    216   __ ret(0);
    217 
    218   CodeDesc desc;
    219   assm.GetCode(&desc);
    220   Code* code = Code::cast(HEAP->CreateCode(
    221       desc,
    222       Code::ComputeFlags(Code::STUB),
    223       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
    224   // don't print the code - our disassembler can't handle cvttsd2si
    225   // instead print bytes
    226   Disassembler::Dump(stdout,
    227                      code->instruction_start(),
    228                      code->instruction_start() + code->instruction_size());
    229   F4 f = FUNCTION_CAST<F4>(code->entry());
    230   int res = f(2.718281828);
    231   ::printf("f() = %d\n", res);
    232   CHECK_EQ(2, res);
    233 }
    234 
    235 
    236 static int baz = 42;
    237 TEST(AssemblerIa325) {
    238   InitializeVM();
    239   v8::HandleScope scope;
    240 
    241   v8::internal::byte buffer[256];
    242   Assembler assm(Isolate::Current(), buffer, sizeof buffer);
    243 
    244   __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE));
    245   __ ret(0);
    246 
    247   CodeDesc desc;
    248   assm.GetCode(&desc);
    249   Code* code = Code::cast(HEAP->CreateCode(
    250       desc,
    251       Code::ComputeFlags(Code::STUB),
    252       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
    253   F0 f = FUNCTION_CAST<F0>(code->entry());
    254   int res = f();
    255   CHECK_EQ(42, res);
    256 }
    257 
    258 
    259 typedef double (*F5)(double x, double y);
    260 
    261 TEST(AssemblerIa326) {
    262   InitializeVM();
    263   if (!CpuFeatures::IsSupported(SSE2)) return;
    264 
    265   v8::HandleScope scope;
    266   CHECK(CpuFeatures::IsSupported(SSE2));
    267   CpuFeatures::Scope fscope(SSE2);
    268   v8::internal::byte buffer[256];
    269   Assembler assm(Isolate::Current(), buffer, sizeof buffer);
    270 
    271   __ movdbl(xmm0, Operand(esp, 1 * kPointerSize));
    272   __ movdbl(xmm1, Operand(esp, 3 * kPointerSize));
    273   __ addsd(xmm0, xmm1);
    274   __ mulsd(xmm0, xmm1);
    275   __ subsd(xmm0, xmm1);
    276   __ divsd(xmm0, xmm1);
    277   // Copy xmm0 to st(0) using eight bytes of stack.
    278   __ sub(esp, Immediate(8));
    279   __ movdbl(Operand(esp, 0), xmm0);
    280   __ fld_d(Operand(esp, 0));
    281   __ add(esp, Immediate(8));
    282   __ ret(0);
    283 
    284   CodeDesc desc;
    285   assm.GetCode(&desc);
    286   Code* code = Code::cast(HEAP->CreateCode(
    287       desc,
    288       Code::ComputeFlags(Code::STUB),
    289       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
    290 #ifdef DEBUG
    291   ::printf("\n---\n");
    292   // don't print the code - our disassembler can't handle SSE instructions
    293   // instead print bytes
    294   Disassembler::Dump(stdout,
    295                      code->instruction_start(),
    296                      code->instruction_start() + code->instruction_size());
    297 #endif
    298   F5 f = FUNCTION_CAST<F5>(code->entry());
    299   double res = f(2.2, 1.1);
    300   ::printf("f() = %f\n", res);
    301   CHECK(2.29 < res && res < 2.31);
    302 }
    303 
    304 
    305 typedef double (*F6)(int x);
    306 
    307 TEST(AssemblerIa328) {
    308   InitializeVM();
    309   if (!CpuFeatures::IsSupported(SSE2)) return;
    310 
    311   v8::HandleScope scope;
    312   CHECK(CpuFeatures::IsSupported(SSE2));
    313   CpuFeatures::Scope fscope(SSE2);
    314   v8::internal::byte buffer[256];
    315   Assembler assm(Isolate::Current(), buffer, sizeof buffer);
    316   __ mov(eax, Operand(esp, 4));
    317   __ cvtsi2sd(xmm0, eax);
    318   // Copy xmm0 to st(0) using eight bytes of stack.
    319   __ sub(esp, Immediate(8));
    320   __ movdbl(Operand(esp, 0), xmm0);
    321   __ fld_d(Operand(esp, 0));
    322   __ add(esp, Immediate(8));
    323   __ ret(0);
    324   CodeDesc desc;
    325   assm.GetCode(&desc);
    326   Code* code = Code::cast(HEAP->CreateCode(
    327       desc,
    328       Code::ComputeFlags(Code::STUB),
    329       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
    330   CHECK(code->IsCode());
    331 #ifdef OBJECT_PRINT
    332   Code::cast(code)->Print();
    333 #endif
    334   F6 f = FUNCTION_CAST<F6>(Code::cast(code)->entry());
    335   double res = f(12);
    336 
    337   ::printf("f() = %f\n", res);
    338   CHECK(11.99 < res && res < 12.001);
    339 }
    340 
    341 
    342 typedef int (*F7)(double x, double y);
    343 
    344 TEST(AssemblerIa329) {
    345   InitializeVM();
    346   v8::HandleScope scope;
    347   v8::internal::byte buffer[256];
    348   MacroAssembler assm(Isolate::Current(), buffer, sizeof buffer);
    349   enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 };
    350   Label equal_l, less_l, greater_l, nan_l;
    351   __ fld_d(Operand(esp, 3 * kPointerSize));
    352   __ fld_d(Operand(esp, 1 * kPointerSize));
    353   __ FCmp();
    354   __ j(parity_even, &nan_l);
    355   __ j(equal, &equal_l);
    356   __ j(below, &less_l);
    357   __ j(above, &greater_l);
    358 
    359   __ mov(eax, kUndefined);
    360   __ ret(0);
    361 
    362   __ bind(&equal_l);
    363   __ mov(eax, kEqual);
    364   __ ret(0);
    365 
    366   __ bind(&greater_l);
    367   __ mov(eax, kGreater);
    368   __ ret(0);
    369 
    370   __ bind(&less_l);
    371   __ mov(eax, kLess);
    372   __ ret(0);
    373 
    374   __ bind(&nan_l);
    375   __ mov(eax, kNaN);
    376   __ ret(0);
    377 
    378 
    379   CodeDesc desc;
    380   assm.GetCode(&desc);
    381   Code* code = Code::cast(HEAP->CreateCode(
    382       desc,
    383       Code::ComputeFlags(Code::STUB),
    384       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
    385   CHECK(code->IsCode());
    386 #ifdef OBJECT_PRINT
    387   Code::cast(code)->Print();
    388 #endif
    389 
    390   F7 f = FUNCTION_CAST<F7>(Code::cast(code)->entry());
    391   CHECK_EQ(kLess, f(1.1, 2.2));
    392   CHECK_EQ(kEqual, f(2.2, 2.2));
    393   CHECK_EQ(kGreater, f(3.3, 2.2));
    394   CHECK_EQ(kNaN, f(OS::nan_value(), 1.1));
    395 }
    396 
    397 
    398 TEST(AssemblerIa3210) {
    399   // Test chaining of label usages within instructions (issue 1644).
    400   InitializeVM();
    401   v8::HandleScope scope;
    402   Assembler assm(Isolate::Current(), NULL, 0);
    403 
    404   Label target;
    405   __ j(equal, &target);
    406   __ j(not_equal, &target);
    407   __ bind(&target);
    408   __ nop();
    409 }
    410 
    411 
    412 TEST(AssemblerMultiByteNop) {
    413   InitializeVM();
    414   v8::HandleScope scope;
    415   v8::internal::byte buffer[1024];
    416   Assembler assm(Isolate::Current(), buffer, sizeof(buffer));
    417   __ push(ebx);
    418   __ push(ecx);
    419   __ push(edx);
    420   __ push(edi);
    421   __ push(esi);
    422   __ mov(eax, 1);
    423   __ mov(ebx, 2);
    424   __ mov(ecx, 3);
    425   __ mov(edx, 4);
    426   __ mov(edi, 5);
    427   __ mov(esi, 6);
    428   for (int i = 0; i < 16; i++) {
    429     int before = assm.pc_offset();
    430     __ Nop(i);
    431     CHECK_EQ(assm.pc_offset() - before, i);
    432   }
    433 
    434   Label fail;
    435   __ cmp(eax, 1);
    436   __ j(not_equal, &fail);
    437   __ cmp(ebx, 2);
    438   __ j(not_equal, &fail);
    439   __ cmp(ecx, 3);
    440   __ j(not_equal, &fail);
    441   __ cmp(edx, 4);
    442   __ j(not_equal, &fail);
    443   __ cmp(edi, 5);
    444   __ j(not_equal, &fail);
    445   __ cmp(esi, 6);
    446   __ j(not_equal, &fail);
    447   __ mov(eax, 42);
    448   __ pop(esi);
    449   __ pop(edi);
    450   __ pop(edx);
    451   __ pop(ecx);
    452   __ pop(ebx);
    453   __ ret(0);
    454   __ bind(&fail);
    455   __ mov(eax, 13);
    456   __ pop(esi);
    457   __ pop(edi);
    458   __ pop(edx);
    459   __ pop(ecx);
    460   __ pop(ebx);
    461   __ ret(0);
    462 
    463   CodeDesc desc;
    464   assm.GetCode(&desc);
    465   Code* code = Code::cast(HEAP->CreateCode(
    466       desc,
    467       Code::ComputeFlags(Code::STUB),
    468       Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
    469   CHECK(code->IsCode());
    470 
    471   F0 f = FUNCTION_CAST<F0>(code->entry());
    472   int res = f();
    473   CHECK_EQ(42, res);
    474 }
    475 
    476 
    477 
    478 
    479 #undef __
    480