1 // Copyright 2006-2008 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(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(desc, 73 NULL, 74 Code::ComputeFlags(Code::STUB), 75 Handle<Object>(Heap::undefined_value())); 76 CHECK(code->IsCode()); 77 #ifdef DEBUG 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(buffer, sizeof buffer); 93 Label L, C; 94 95 __ mov(edx, Operand(esp, 4)); 96 __ xor_(eax, Operand(eax)); // clear eax 97 __ jmp(&C); 98 99 __ bind(&L); 100 __ add(eax, Operand(edx)); 101 __ sub(Operand(edx), Immediate(1)); 102 103 __ bind(&C); 104 __ test(edx, Operand(edx)); 105 __ j(not_zero, &L, taken); 106 __ ret(0); 107 108 CodeDesc desc; 109 assm.GetCode(&desc); 110 Object* code = Heap::CreateCode(desc, 111 NULL, 112 Code::ComputeFlags(Code::STUB), 113 Handle<Object>(Heap::undefined_value())); 114 CHECK(code->IsCode()); 115 #ifdef DEBUG 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(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, Operand(edx)); 139 __ sub(Operand(edx), Immediate(1)); 140 141 __ bind(&C); 142 __ test(edx, Operand(edx)); 143 __ j(not_zero, &L, taken); 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(desc, 153 NULL, 154 Code::ComputeFlags(Code::STUB), 155 Handle<Object>(Heap::undefined_value())); 156 CHECK(code->IsCode()); 157 #ifdef DEBUG 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 v8::HandleScope scope; 172 173 v8::internal::byte buffer[256]; 174 Assembler assm(buffer, sizeof buffer); 175 176 CHECK(CpuFeatures::IsSupported(SSE2)); 177 { CpuFeatures::Scope fscope(SSE2); 178 __ cvttss2si(eax, Operand(esp, 4)); 179 __ ret(0); 180 } 181 182 CodeDesc desc; 183 assm.GetCode(&desc); 184 Code* code = 185 Code::cast(Heap::CreateCode(desc, 186 NULL, 187 Code::ComputeFlags(Code::STUB), 188 Handle<Object>(Heap::undefined_value()))); 189 // don't print the code - our disassembler can't handle cvttss2si 190 // instead print bytes 191 Disassembler::Dump(stdout, 192 code->instruction_start(), 193 code->instruction_start() + code->instruction_size()); 194 F3 f = FUNCTION_CAST<F3>(code->entry()); 195 int res = f(static_cast<float>(-3.1415)); 196 ::printf("f() = %d\n", res); 197 CHECK_EQ(-3, res); 198 } 199 200 201 typedef int (*F4)(double x); 202 203 TEST(AssemblerIa324) { 204 InitializeVM(); 205 v8::HandleScope scope; 206 207 v8::internal::byte buffer[256]; 208 Assembler assm(buffer, sizeof buffer); 209 210 CHECK(CpuFeatures::IsSupported(SSE2)); 211 CpuFeatures::Scope fscope(SSE2); 212 __ cvttsd2si(eax, Operand(esp, 4)); 213 __ ret(0); 214 215 CodeDesc desc; 216 assm.GetCode(&desc); 217 Code* code = 218 Code::cast(Heap::CreateCode(desc, 219 NULL, 220 Code::ComputeFlags(Code::STUB), 221 Handle<Object>(Heap::undefined_value()))); 222 // don't print the code - our disassembler can't handle cvttsd2si 223 // instead print bytes 224 Disassembler::Dump(stdout, 225 code->instruction_start(), 226 code->instruction_start() + code->instruction_size()); 227 F4 f = FUNCTION_CAST<F4>(code->entry()); 228 int res = f(2.718281828); 229 ::printf("f() = %d\n", res); 230 CHECK_EQ(2, res); 231 } 232 233 234 static int baz = 42; 235 TEST(AssemblerIa325) { 236 InitializeVM(); 237 v8::HandleScope scope; 238 239 v8::internal::byte buffer[256]; 240 Assembler assm(buffer, sizeof buffer); 241 242 __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE)); 243 __ ret(0); 244 245 CodeDesc desc; 246 assm.GetCode(&desc); 247 Code* code = 248 Code::cast(Heap::CreateCode(desc, 249 NULL, 250 Code::ComputeFlags(Code::STUB), 251 Handle<Object>(Heap::undefined_value()))); 252 F0 f = FUNCTION_CAST<F0>(code->entry()); 253 int res = f(); 254 CHECK_EQ(42, res); 255 } 256 257 258 typedef double (*F5)(double x, double y); 259 260 TEST(AssemblerIa326) { 261 InitializeVM(); 262 v8::HandleScope scope; 263 CHECK(CpuFeatures::IsSupported(SSE2)); 264 CpuFeatures::Scope fscope(SSE2); 265 v8::internal::byte buffer[256]; 266 Assembler assm(buffer, sizeof buffer); 267 268 __ movdbl(xmm0, Operand(esp, 1 * kPointerSize)); 269 __ movdbl(xmm1, Operand(esp, 3 * kPointerSize)); 270 __ addsd(xmm0, xmm1); 271 __ mulsd(xmm0, xmm1); 272 __ subsd(xmm0, xmm1); 273 __ divsd(xmm0, xmm1); 274 // Copy xmm0 to st(0) using eight bytes of stack. 275 __ sub(Operand(esp), Immediate(8)); 276 __ movdbl(Operand(esp, 0), xmm0); 277 __ fld_d(Operand(esp, 0)); 278 __ add(Operand(esp), Immediate(8)); 279 __ ret(0); 280 281 CodeDesc desc; 282 assm.GetCode(&desc); 283 Code* code = 284 Code::cast(Heap::CreateCode(desc, 285 NULL, 286 Code::ComputeFlags(Code::STUB), 287 Handle<Object>(Heap::undefined_value()))); 288 #ifdef DEBUG 289 ::printf("\n---\n"); 290 // don't print the code - our disassembler can't handle SSE instructions 291 // instead print bytes 292 Disassembler::Dump(stdout, 293 code->instruction_start(), 294 code->instruction_start() + code->instruction_size()); 295 #endif 296 F5 f = FUNCTION_CAST<F5>(code->entry()); 297 double res = f(2.2, 1.1); 298 ::printf("f() = %f\n", res); 299 CHECK(2.29 < res && res < 2.31); 300 } 301 302 303 typedef double (*F6)(int x); 304 305 TEST(AssemblerIa328) { 306 InitializeVM(); 307 v8::HandleScope scope; 308 CHECK(CpuFeatures::IsSupported(SSE2)); 309 CpuFeatures::Scope fscope(SSE2); 310 v8::internal::byte buffer[256]; 311 Assembler assm(buffer, sizeof buffer); 312 __ mov(eax, Operand(esp, 4)); 313 __ cvtsi2sd(xmm0, Operand(eax)); 314 // Copy xmm0 to st(0) using eight bytes of stack. 315 __ sub(Operand(esp), Immediate(8)); 316 __ movdbl(Operand(esp, 0), xmm0); 317 __ fld_d(Operand(esp, 0)); 318 __ add(Operand(esp), Immediate(8)); 319 __ ret(0); 320 CodeDesc desc; 321 assm.GetCode(&desc); 322 Code* code = 323 Code::cast(Heap::CreateCode(desc, 324 NULL, 325 Code::ComputeFlags(Code::STUB), 326 Handle<Object>(Heap::undefined_value()))); 327 CHECK(code->IsCode()); 328 #ifdef DEBUG 329 Code::cast(code)->Print(); 330 #endif 331 F6 f = FUNCTION_CAST<F6>(Code::cast(code)->entry()); 332 double res = f(12); 333 334 ::printf("f() = %f\n", res); 335 CHECK(11.99 < res && res < 12.001); 336 } 337 338 339 typedef int (*F7)(double x, double y); 340 341 TEST(AssemblerIa329) { 342 InitializeVM(); 343 v8::HandleScope scope; 344 v8::internal::byte buffer[256]; 345 MacroAssembler assm(buffer, sizeof buffer); 346 enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 }; 347 Label equal_l, less_l, greater_l, nan_l; 348 __ fld_d(Operand(esp, 3 * kPointerSize)); 349 __ fld_d(Operand(esp, 1 * kPointerSize)); 350 __ FCmp(); 351 __ j(parity_even, &nan_l, taken); 352 __ j(equal, &equal_l, taken); 353 __ j(below, &less_l, taken); 354 __ j(above, &greater_l, taken); 355 356 __ mov(eax, kUndefined); 357 __ ret(0); 358 359 __ bind(&equal_l); 360 __ mov(eax, kEqual); 361 __ ret(0); 362 363 __ bind(&greater_l); 364 __ mov(eax, kGreater); 365 __ ret(0); 366 367 __ bind(&less_l); 368 __ mov(eax, kLess); 369 __ ret(0); 370 371 __ bind(&nan_l); 372 __ mov(eax, kNaN); 373 __ ret(0); 374 375 376 CodeDesc desc; 377 assm.GetCode(&desc); 378 Code* code = 379 Code::cast(Heap::CreateCode(desc, 380 NULL, 381 Code::ComputeFlags(Code::STUB), 382 Handle<Object>(Heap::undefined_value()))); 383 CHECK(code->IsCode()); 384 #ifdef DEBUG 385 Code::cast(code)->Print(); 386 #endif 387 388 F7 f = FUNCTION_CAST<F7>(Code::cast(code)->entry()); 389 CHECK_EQ(kLess, f(1.1, 2.2)); 390 CHECK_EQ(kEqual, f(2.2, 2.2)); 391 CHECK_EQ(kGreater, f(3.3, 2.2)); 392 CHECK_EQ(kNaN, f(OS::nan_value(), 1.1)); 393 } 394 395 #undef __ 396