| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 #include <stdlib.h> | 28 #include <stdlib.h> |
| 29 | 29 |
| 30 #include "v8.h" | 30 #include "v8.h" |
| 31 | 31 |
| 32 #include "macro-assembler.h" | 32 #include "macro-assembler.h" |
| 33 #include "factory.h" | 33 #include "factory.h" |
| 34 #include "platform.h" | 34 #include "platform.h" |
| 35 #include "serialize.h" | 35 #include "serialize.h" |
| 36 #include "cctest.h" | 36 #include "cctest.h" |
| 37 | 37 |
| 38 using v8::internal::Assembler; | 38 using namespace v8::internal; |
| 39 using v8::internal::Code; | |
| 40 using v8::internal::CodeDesc; | |
| 41 using v8::internal::FUNCTION_CAST; | |
| 42 using v8::internal::Immediate; | |
| 43 using v8::internal::Isolate; | |
| 44 using v8::internal::Label; | |
| 45 using v8::internal::OS; | |
| 46 using v8::internal::Operand; | |
| 47 using v8::internal::byte; | |
| 48 using v8::internal::greater; | |
| 49 using v8::internal::less_equal; | |
| 50 using v8::internal::equal; | |
| 51 using v8::internal::not_equal; | |
| 52 using v8::internal::r13; | |
| 53 using v8::internal::r15; | |
| 54 using v8::internal::r8; | |
| 55 using v8::internal::r9; | |
| 56 using v8::internal::rax; | |
| 57 using v8::internal::rbx; | |
| 58 using v8::internal::rbp; | |
| 59 using v8::internal::rcx; | |
| 60 using v8::internal::rdi; | |
| 61 using v8::internal::rdx; | |
| 62 using v8::internal::rsi; | |
| 63 using v8::internal::rsp; | |
| 64 using v8::internal::times_1; | |
| 65 using v8::internal::xmm0; | |
| 66 | 39 |
| 67 // Test the x64 assembler by compiling some simple functions into | 40 // Test the x64 assembler by compiling some simple functions into |
| 68 // a buffer and executing them. These tests do not initialize the | 41 // a buffer and executing them. These tests do not initialize the |
| 69 // V8 library, create a context, or use any V8 objects. | 42 // V8 library, create a context, or use any V8 objects. |
| 70 // The AMD64 calling convention is used, with the first six arguments | 43 // The AMD64 calling convention is used, with the first six arguments |
| 71 // in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in | 44 // in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in |
| 72 // the XMM registers. The return value is in RAX. | 45 // the XMM registers. The return value is in RAX. |
| 73 // This calling convention is used on Linux, with GCC, and on Mac OS, | 46 // This calling convention is used on Linux, with GCC, and on Mac OS, |
| 74 // with GCC. A different convention is used on 64-bit windows, | 47 // with GCC. A different convention is used on 64-bit windows, |
| 75 // where the first four integer arguments are passed in RCX, RDX, R8 and R9. | 48 // where the first four integer arguments are passed in RCX, RDX, R8 and R9. |
| 76 | 49 |
| 77 typedef int (*F0)(); | 50 typedef int (*F0)(); |
| 78 typedef int (*F1)(int64_t x); | 51 typedef int (*F1)(int64_t x); |
| 79 typedef int (*F2)(int64_t x, int64_t y); | 52 typedef int (*F2)(int64_t x, int64_t y); |
| 80 | 53 |
| 81 #ifdef _WIN64 | 54 #ifdef _WIN64 |
| 82 static const v8::internal::Register arg1 = rcx; | 55 static const v8::internal::Register arg1 = rcx; |
| 83 static const v8::internal::Register arg2 = rdx; | 56 static const v8::internal::Register arg2 = rdx; |
| 84 #else | 57 #else |
| 85 static const v8::internal::Register arg1 = rdi; | 58 static const v8::internal::Register arg1 = rdi; |
| 86 static const v8::internal::Register arg2 = rsi; | 59 static const v8::internal::Register arg2 = rsi; |
| 87 #endif | 60 #endif |
| 88 | 61 |
| 89 #define __ assm. | 62 #define __ assm. |
| 90 | 63 |
| 91 | 64 |
| 92 TEST(AssemblerX64ReturnOperation) { | 65 TEST(AssemblerX64ReturnOperation) { |
| 93 // Allocate an executable page of memory. | 66 // Allocate an executable page of memory. |
| 94 size_t actual_size; | 67 size_t actual_size; |
| 95 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 68 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
| 96 &actual_size, | 69 Assembler::kMinimalBufferSize, |
| 97 true)); | 70 &actual_size, |
| 71 VirtualMemory::EXECUTABLE)); |
| 98 CHECK(buffer); | 72 CHECK(buffer); |
| 99 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 73 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
| 100 | 74 |
| 101 // Assemble a simple function that copies argument 2 and returns it. | 75 // Assemble a simple function that copies argument 2 and returns it. |
| 102 __ movq(rax, arg2); | 76 __ movq(rax, arg2); |
| 103 __ nop(); | 77 __ nop(); |
| 104 __ ret(0); | 78 __ ret(0); |
| 105 | 79 |
| 106 CodeDesc desc; | 80 CodeDesc desc; |
| 107 assm.GetCode(&desc); | 81 assm.GetCode(&desc); |
| 108 // Call the function from C++. | 82 // Call the function from C++. |
| 109 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 83 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
| 110 CHECK_EQ(2, result); | 84 CHECK_EQ(2, result); |
| 111 } | 85 } |
| 112 | 86 |
| 113 | 87 |
| 114 TEST(AssemblerX64StackOperations) { | 88 TEST(AssemblerX64StackOperations) { |
| 115 // Allocate an executable page of memory. | 89 // Allocate an executable page of memory. |
| 116 size_t actual_size; | 90 size_t actual_size; |
| 117 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 91 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
| 118 &actual_size, | 92 Assembler::kMinimalBufferSize, |
| 119 true)); | 93 &actual_size, |
| 94 VirtualMemory::EXECUTABLE)); |
| 120 CHECK(buffer); | 95 CHECK(buffer); |
| 121 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 96 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
| 122 | 97 |
| 123 // Assemble a simple function that copies argument 2 and returns it. | 98 // Assemble a simple function that copies argument 2 and returns it. |
| 124 // We compile without stack frame pointers, so the gdb debugger shows | 99 // We compile without stack frame pointers, so the gdb debugger shows |
| 125 // incorrect stack frames when debugging this function (which has them). | 100 // incorrect stack frames when debugging this function (which has them). |
| 126 __ push(rbp); | 101 __ push(rbp); |
| 127 __ movq(rbp, rsp); | 102 __ movq(rbp, rsp); |
| 128 __ push(arg2); // Value at (rbp - 8) | 103 __ push(arg2); // Value at (rbp - 8) |
| 129 __ push(arg2); // Value at (rbp - 16) | 104 __ push(arg2); // Value at (rbp - 16) |
| 130 __ push(arg1); // Value at (rbp - 24) | 105 __ push(arg1); // Value at (rbp - 24) |
| 131 __ pop(rax); | 106 __ pop(rax); |
| 132 __ pop(rax); | 107 __ pop(rax); |
| 133 __ pop(rax); | 108 __ pop(rax); |
| 134 __ pop(rbp); | 109 __ pop(rbp); |
| 135 __ nop(); | 110 __ nop(); |
| 136 __ ret(0); | 111 __ ret(0); |
| 137 | 112 |
| 138 CodeDesc desc; | 113 CodeDesc desc; |
| 139 assm.GetCode(&desc); | 114 assm.GetCode(&desc); |
| 140 // Call the function from C++. | 115 // Call the function from C++. |
| 141 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 116 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
| 142 CHECK_EQ(2, result); | 117 CHECK_EQ(2, result); |
| 143 } | 118 } |
| 144 | 119 |
| 145 | 120 |
| 146 TEST(AssemblerX64ArithmeticOperations) { | 121 TEST(AssemblerX64ArithmeticOperations) { |
| 147 // Allocate an executable page of memory. | 122 // Allocate an executable page of memory. |
| 148 size_t actual_size; | 123 size_t actual_size; |
| 149 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 124 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
| 150 &actual_size, | 125 Assembler::kMinimalBufferSize, |
| 151 true)); | 126 &actual_size, |
| 127 VirtualMemory::EXECUTABLE)); |
| 152 CHECK(buffer); | 128 CHECK(buffer); |
| 153 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 129 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
| 154 | 130 |
| 155 // Assemble a simple function that adds arguments returning the sum. | 131 // Assemble a simple function that adds arguments returning the sum. |
| 156 __ movq(rax, arg2); | 132 __ movq(rax, arg2); |
| 157 __ addq(rax, arg1); | 133 __ addq(rax, arg1); |
| 158 __ ret(0); | 134 __ ret(0); |
| 159 | 135 |
| 160 CodeDesc desc; | 136 CodeDesc desc; |
| 161 assm.GetCode(&desc); | 137 assm.GetCode(&desc); |
| 162 // Call the function from C++. | 138 // Call the function from C++. |
| 163 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 139 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
| 164 CHECK_EQ(5, result); | 140 CHECK_EQ(5, result); |
| 165 } | 141 } |
| 166 | 142 |
| 167 | 143 |
| 168 TEST(AssemblerX64ImulOperation) { | 144 TEST(AssemblerX64ImulOperation) { |
| 169 // Allocate an executable page of memory. | 145 // Allocate an executable page of memory. |
| 170 size_t actual_size; | 146 size_t actual_size; |
| 171 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 147 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
| 172 &actual_size, | 148 Assembler::kMinimalBufferSize, |
| 173 true)); | 149 &actual_size, |
| 150 VirtualMemory::EXECUTABLE)); |
| 174 CHECK(buffer); | 151 CHECK(buffer); |
| 175 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 152 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
| 176 | 153 |
| 177 // Assemble a simple function that multiplies arguments returning the high | 154 // Assemble a simple function that multiplies arguments returning the high |
| 178 // word. | 155 // word. |
| 179 __ movq(rax, arg2); | 156 __ movq(rax, arg2); |
| 180 __ imul(arg1); | 157 __ imul(arg1); |
| 181 __ movq(rax, rdx); | 158 __ movq(rax, rdx); |
| 182 __ ret(0); | 159 __ ret(0); |
| 183 | 160 |
| 184 CodeDesc desc; | 161 CodeDesc desc; |
| 185 assm.GetCode(&desc); | 162 assm.GetCode(&desc); |
| 186 // Call the function from C++. | 163 // Call the function from C++. |
| 187 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 164 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
| 188 CHECK_EQ(0, result); | 165 CHECK_EQ(0, result); |
| 189 result = FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l); | 166 result = FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l); |
| 190 CHECK_EQ(1, result); | 167 CHECK_EQ(1, result); |
| 191 result = FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l); | 168 result = FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l); |
| 192 CHECK_EQ(-1, result); | 169 CHECK_EQ(-1, result); |
| 193 } | 170 } |
| 194 | 171 |
| 195 | 172 |
| 196 TEST(AssemblerX64MemoryOperands) { | 173 TEST(AssemblerX64MemoryOperands) { |
| 197 // Allocate an executable page of memory. | 174 // Allocate an executable page of memory. |
| 198 size_t actual_size; | 175 size_t actual_size; |
| 199 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 176 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
| 200 &actual_size, | 177 Assembler::kMinimalBufferSize, |
| 201 true)); | 178 &actual_size, |
| 179 VirtualMemory::EXECUTABLE)); |
| 202 CHECK(buffer); | 180 CHECK(buffer); |
| 203 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 181 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
| 204 | 182 |
| 205 // Assemble a simple function that copies argument 2 and returns it. | 183 // Assemble a simple function that copies argument 2 and returns it. |
| 206 __ push(rbp); | 184 __ push(rbp); |
| 207 __ movq(rbp, rsp); | 185 __ movq(rbp, rsp); |
| 208 | 186 |
| 209 __ push(arg2); // Value at (rbp - 8) | 187 __ push(arg2); // Value at (rbp - 8) |
| 210 __ push(arg2); // Value at (rbp - 16) | 188 __ push(arg2); // Value at (rbp - 16) |
| 211 __ push(arg1); // Value at (rbp - 24) | 189 __ push(arg1); // Value at (rbp - 24) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 223 assm.GetCode(&desc); | 201 assm.GetCode(&desc); |
| 224 // Call the function from C++. | 202 // Call the function from C++. |
| 225 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 203 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
| 226 CHECK_EQ(3, result); | 204 CHECK_EQ(3, result); |
| 227 } | 205 } |
| 228 | 206 |
| 229 | 207 |
| 230 TEST(AssemblerX64ControlFlow) { | 208 TEST(AssemblerX64ControlFlow) { |
| 231 // Allocate an executable page of memory. | 209 // Allocate an executable page of memory. |
| 232 size_t actual_size; | 210 size_t actual_size; |
| 233 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 211 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
| 234 &actual_size, | 212 Assembler::kMinimalBufferSize, |
| 235 true)); | 213 &actual_size, |
| 214 VirtualMemory::EXECUTABLE)); |
| 236 CHECK(buffer); | 215 CHECK(buffer); |
| 237 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 216 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
| 238 | 217 |
| 239 // Assemble a simple function that copies argument 1 and returns it. | 218 // Assemble a simple function that copies argument 1 and returns it. |
| 240 __ push(rbp); | 219 __ push(rbp); |
| 241 | 220 |
| 242 __ movq(rbp, rsp); | 221 __ movq(rbp, rsp); |
| 243 __ movq(rax, arg1); | 222 __ movq(rax, arg1); |
| 244 Label target; | 223 Label target; |
| 245 __ jmp(&target); | 224 __ jmp(&target); |
| 246 __ movq(rax, arg2); | 225 __ movq(rax, arg2); |
| 247 __ bind(&target); | 226 __ bind(&target); |
| 248 __ pop(rbp); | 227 __ pop(rbp); |
| 249 __ ret(0); | 228 __ ret(0); |
| 250 | 229 |
| 251 CodeDesc desc; | 230 CodeDesc desc; |
| 252 assm.GetCode(&desc); | 231 assm.GetCode(&desc); |
| 253 // Call the function from C++. | 232 // Call the function from C++. |
| 254 int result = FUNCTION_CAST<F2>(buffer)(3, 2); | 233 int result = FUNCTION_CAST<F2>(buffer)(3, 2); |
| 255 CHECK_EQ(3, result); | 234 CHECK_EQ(3, result); |
| 256 } | 235 } |
| 257 | 236 |
| 258 | 237 |
| 259 TEST(AssemblerX64LoopImmediates) { | 238 TEST(AssemblerX64LoopImmediates) { |
| 260 // Allocate an executable page of memory. | 239 // Allocate an executable page of memory. |
| 261 size_t actual_size; | 240 size_t actual_size; |
| 262 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, | 241 byte* buffer = static_cast<byte*>(VirtualMemory::AllocateRegion( |
| 263 &actual_size, | 242 Assembler::kMinimalBufferSize, |
| 264 true)); | 243 &actual_size, |
| 244 VirtualMemory::EXECUTABLE)); |
| 265 CHECK(buffer); | 245 CHECK(buffer); |
| 266 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); | 246 Assembler assm(Isolate::Current(), buffer, static_cast<int>(actual_size)); |
| 267 // Assemble two loops using rax as counter, and verify the ending counts. | 247 // Assemble two loops using rax as counter, and verify the ending counts. |
| 268 Label Fail; | 248 Label Fail; |
| 269 __ movq(rax, Immediate(-3)); | 249 __ movq(rax, Immediate(-3)); |
| 270 Label Loop1_test; | 250 Label Loop1_test; |
| 271 Label Loop1_body; | 251 Label Loop1_body; |
| 272 __ jmp(&Loop1_test); | 252 __ jmp(&Loop1_test); |
| 273 __ bind(&Loop1_body); | 253 __ bind(&Loop1_body); |
| 274 __ addq(rax, Immediate(7)); | 254 __ addq(rax, Immediate(7)); |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 | 491 |
| 512 // The mask should be 0b1000. | 492 // The mask should be 0b1000. |
| 513 CHECK_EQ(8, result->Int32Value()); | 493 CHECK_EQ(8, result->Int32Value()); |
| 514 } | 494 } |
| 515 | 495 |
| 516 #undef ELEMENT_COUNT | 496 #undef ELEMENT_COUNT |
| 517 #endif // __GNUC__ | 497 #endif // __GNUC__ |
| 518 | 498 |
| 519 | 499 |
| 520 #undef __ | 500 #undef __ |
| OLD | NEW |