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 "src/v8.h" 31 32#include "src/base/platform/platform.h" 33#include "src/disassembler.h" 34#include "src/factory.h" 35#include "src/macro-assembler.h" 36#include "src/ostreams.h" 37#include "src/serialize.h" 38#include "test/cctest/cctest.h" 39 40using namespace v8::internal; 41 42 43typedef int (*F0)(); 44typedef int (*F1)(int x); 45typedef int (*F2)(int x, int y); 46 47 48#define __ assm. 49 50TEST(AssemblerIa320) { 51 CcTest::InitializeVM(); 52 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 53 HandleScope scope(isolate); 54 55 v8::internal::byte buffer[256]; 56 Assembler assm(isolate, buffer, sizeof buffer); 57 58 __ mov(eax, Operand(esp, 4)); 59 __ add(eax, Operand(esp, 8)); 60 __ ret(0); 61 62 CodeDesc desc; 63 assm.GetCode(&desc); 64 Handle<Code> code = isolate->factory()->NewCode( 65 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 66#ifdef OBJECT_PRINT 67 OFStream os(stdout); 68 code->Print(os); 69#endif 70 F2 f = FUNCTION_CAST<F2>(code->entry()); 71 int res = f(3, 4); 72 ::printf("f() = %d\n", res); 73 CHECK_EQ(7, res); 74} 75 76 77TEST(AssemblerIa321) { 78 CcTest::InitializeVM(); 79 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 80 HandleScope scope(isolate); 81 82 v8::internal::byte buffer[256]; 83 Assembler assm(isolate, buffer, sizeof buffer); 84 Label L, C; 85 86 __ mov(edx, Operand(esp, 4)); 87 __ xor_(eax, eax); // clear eax 88 __ jmp(&C); 89 90 __ bind(&L); 91 __ add(eax, edx); 92 __ sub(edx, Immediate(1)); 93 94 __ bind(&C); 95 __ test(edx, edx); 96 __ j(not_zero, &L); 97 __ ret(0); 98 99 CodeDesc desc; 100 assm.GetCode(&desc); 101 Handle<Code> code = isolate->factory()->NewCode( 102 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 103#ifdef OBJECT_PRINT 104 OFStream os(stdout); 105 code->Print(os); 106#endif 107 F1 f = FUNCTION_CAST<F1>(code->entry()); 108 int res = f(100); 109 ::printf("f() = %d\n", res); 110 CHECK_EQ(5050, res); 111} 112 113 114TEST(AssemblerIa322) { 115 CcTest::InitializeVM(); 116 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 117 HandleScope scope(isolate); 118 119 v8::internal::byte buffer[256]; 120 Assembler assm(isolate, buffer, sizeof buffer); 121 Label L, C; 122 123 __ mov(edx, Operand(esp, 4)); 124 __ mov(eax, 1); 125 __ jmp(&C); 126 127 __ bind(&L); 128 __ imul(eax, edx); 129 __ sub(edx, Immediate(1)); 130 131 __ bind(&C); 132 __ test(edx, edx); 133 __ j(not_zero, &L); 134 __ ret(0); 135 136 // some relocated stuff here, not executed 137 __ mov(eax, isolate->factory()->true_value()); 138 __ jmp(NULL, RelocInfo::RUNTIME_ENTRY); 139 140 CodeDesc desc; 141 assm.GetCode(&desc); 142 Handle<Code> code = isolate->factory()->NewCode( 143 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 144#ifdef OBJECT_PRINT 145 OFStream os(stdout); 146 code->Print(os); 147#endif 148 F1 f = FUNCTION_CAST<F1>(code->entry()); 149 int res = f(10); 150 ::printf("f() = %d\n", res); 151 CHECK_EQ(3628800, res); 152} 153 154 155typedef int (*F3)(float x); 156 157TEST(AssemblerIa323) { 158 CcTest::InitializeVM(); 159 160 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 161 HandleScope scope(isolate); 162 163 v8::internal::byte buffer[256]; 164 Assembler assm(isolate, buffer, sizeof buffer); 165 166 __ cvttss2si(eax, Operand(esp, 4)); 167 __ ret(0); 168 169 CodeDesc desc; 170 assm.GetCode(&desc); 171 Handle<Code> code = isolate->factory()->NewCode( 172 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 173 // don't print the code - our disassembler can't handle cvttss2si 174 // instead print bytes 175 Disassembler::Dump(stdout, 176 code->instruction_start(), 177 code->instruction_start() + code->instruction_size()); 178 F3 f = FUNCTION_CAST<F3>(code->entry()); 179 int res = f(static_cast<float>(-3.1415)); 180 ::printf("f() = %d\n", res); 181 CHECK_EQ(-3, res); 182} 183 184 185typedef int (*F4)(double x); 186 187TEST(AssemblerIa324) { 188 CcTest::InitializeVM(); 189 190 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 191 HandleScope scope(isolate); 192 193 v8::internal::byte buffer[256]; 194 Assembler assm(isolate, buffer, sizeof buffer); 195 196 __ cvttsd2si(eax, Operand(esp, 4)); 197 __ ret(0); 198 199 CodeDesc desc; 200 assm.GetCode(&desc); 201 Handle<Code> code = isolate->factory()->NewCode( 202 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 203 // don't print the code - our disassembler can't handle cvttsd2si 204 // instead print bytes 205 Disassembler::Dump(stdout, 206 code->instruction_start(), 207 code->instruction_start() + code->instruction_size()); 208 F4 f = FUNCTION_CAST<F4>(code->entry()); 209 int res = f(2.718281828); 210 ::printf("f() = %d\n", res); 211 CHECK_EQ(2, res); 212} 213 214 215static int baz = 42; 216TEST(AssemblerIa325) { 217 CcTest::InitializeVM(); 218 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 219 HandleScope scope(isolate); 220 221 v8::internal::byte buffer[256]; 222 Assembler assm(isolate, buffer, sizeof buffer); 223 224 __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE32)); 225 __ ret(0); 226 227 CodeDesc desc; 228 assm.GetCode(&desc); 229 Handle<Code> code = isolate->factory()->NewCode( 230 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 231 F0 f = FUNCTION_CAST<F0>(code->entry()); 232 int res = f(); 233 CHECK_EQ(42, res); 234} 235 236 237typedef double (*F5)(double x, double y); 238 239TEST(AssemblerIa326) { 240 CcTest::InitializeVM(); 241 242 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 243 HandleScope scope(isolate); 244 v8::internal::byte buffer[256]; 245 Assembler assm(isolate, buffer, sizeof buffer); 246 247 __ movsd(xmm0, Operand(esp, 1 * kPointerSize)); 248 __ movsd(xmm1, Operand(esp, 3 * kPointerSize)); 249 __ addsd(xmm0, xmm1); 250 __ mulsd(xmm0, xmm1); 251 __ subsd(xmm0, xmm1); 252 __ divsd(xmm0, xmm1); 253 // Copy xmm0 to st(0) using eight bytes of stack. 254 __ sub(esp, Immediate(8)); 255 __ movsd(Operand(esp, 0), xmm0); 256 __ fld_d(Operand(esp, 0)); 257 __ add(esp, Immediate(8)); 258 __ ret(0); 259 260 CodeDesc desc; 261 assm.GetCode(&desc); 262 Handle<Code> code = isolate->factory()->NewCode( 263 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 264#ifdef DEBUG 265 ::printf("\n---\n"); 266 // don't print the code - our disassembler can't handle SSE instructions 267 // instead print bytes 268 Disassembler::Dump(stdout, 269 code->instruction_start(), 270 code->instruction_start() + code->instruction_size()); 271#endif 272 F5 f = FUNCTION_CAST<F5>(code->entry()); 273 double res = f(2.2, 1.1); 274 ::printf("f() = %f\n", res); 275 CHECK(2.29 < res && res < 2.31); 276} 277 278 279typedef double (*F6)(int x); 280 281TEST(AssemblerIa328) { 282 CcTest::InitializeVM(); 283 284 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 285 HandleScope scope(isolate); 286 v8::internal::byte buffer[256]; 287 Assembler assm(isolate, buffer, sizeof buffer); 288 __ mov(eax, Operand(esp, 4)); 289 __ cvtsi2sd(xmm0, eax); 290 // Copy xmm0 to st(0) using eight bytes of stack. 291 __ sub(esp, Immediate(8)); 292 __ movsd(Operand(esp, 0), xmm0); 293 __ fld_d(Operand(esp, 0)); 294 __ add(esp, Immediate(8)); 295 __ ret(0); 296 CodeDesc desc; 297 assm.GetCode(&desc); 298 Handle<Code> code = isolate->factory()->NewCode( 299 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 300#ifdef OBJECT_PRINT 301 OFStream os(stdout); 302 code->Print(os); 303#endif 304 F6 f = FUNCTION_CAST<F6>(code->entry()); 305 double res = f(12); 306 307 ::printf("f() = %f\n", res); 308 CHECK(11.99 < res && res < 12.001); 309} 310 311 312typedef int (*F7)(double x, double y); 313 314TEST(AssemblerIa329) { 315 CcTest::InitializeVM(); 316 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 317 HandleScope scope(isolate); 318 v8::internal::byte buffer[256]; 319 MacroAssembler assm(isolate, buffer, sizeof buffer); 320 enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 }; 321 Label equal_l, less_l, greater_l, nan_l; 322 __ fld_d(Operand(esp, 3 * kPointerSize)); 323 __ fld_d(Operand(esp, 1 * kPointerSize)); 324 __ FCmp(); 325 __ j(parity_even, &nan_l); 326 __ j(equal, &equal_l); 327 __ j(below, &less_l); 328 __ j(above, &greater_l); 329 330 __ mov(eax, kUndefined); 331 __ ret(0); 332 333 __ bind(&equal_l); 334 __ mov(eax, kEqual); 335 __ ret(0); 336 337 __ bind(&greater_l); 338 __ mov(eax, kGreater); 339 __ ret(0); 340 341 __ bind(&less_l); 342 __ mov(eax, kLess); 343 __ ret(0); 344 345 __ bind(&nan_l); 346 __ mov(eax, kNaN); 347 __ ret(0); 348 349 350 CodeDesc desc; 351 assm.GetCode(&desc); 352 Handle<Code> code = isolate->factory()->NewCode( 353 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 354#ifdef OBJECT_PRINT 355 OFStream os(stdout); 356 code->Print(os); 357#endif 358 359 F7 f = FUNCTION_CAST<F7>(code->entry()); 360 CHECK_EQ(kLess, f(1.1, 2.2)); 361 CHECK_EQ(kEqual, f(2.2, 2.2)); 362 CHECK_EQ(kGreater, f(3.3, 2.2)); 363 CHECK_EQ(kNaN, f(v8::base::OS::nan_value(), 1.1)); 364} 365 366 367TEST(AssemblerIa3210) { 368 // Test chaining of label usages within instructions (issue 1644). 369 CcTest::InitializeVM(); 370 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 371 HandleScope scope(isolate); 372 Assembler assm(isolate, NULL, 0); 373 374 Label target; 375 __ j(equal, &target); 376 __ j(not_equal, &target); 377 __ bind(&target); 378 __ nop(); 379} 380 381 382TEST(AssemblerMultiByteNop) { 383 CcTest::InitializeVM(); 384 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 385 HandleScope scope(isolate); 386 v8::internal::byte buffer[1024]; 387 Assembler assm(isolate, buffer, sizeof(buffer)); 388 __ push(ebx); 389 __ push(ecx); 390 __ push(edx); 391 __ push(edi); 392 __ push(esi); 393 __ mov(eax, 1); 394 __ mov(ebx, 2); 395 __ mov(ecx, 3); 396 __ mov(edx, 4); 397 __ mov(edi, 5); 398 __ mov(esi, 6); 399 for (int i = 0; i < 16; i++) { 400 int before = assm.pc_offset(); 401 __ Nop(i); 402 CHECK_EQ(assm.pc_offset() - before, i); 403 } 404 405 Label fail; 406 __ cmp(eax, 1); 407 __ j(not_equal, &fail); 408 __ cmp(ebx, 2); 409 __ j(not_equal, &fail); 410 __ cmp(ecx, 3); 411 __ j(not_equal, &fail); 412 __ cmp(edx, 4); 413 __ j(not_equal, &fail); 414 __ cmp(edi, 5); 415 __ j(not_equal, &fail); 416 __ cmp(esi, 6); 417 __ j(not_equal, &fail); 418 __ mov(eax, 42); 419 __ pop(esi); 420 __ pop(edi); 421 __ pop(edx); 422 __ pop(ecx); 423 __ pop(ebx); 424 __ ret(0); 425 __ bind(&fail); 426 __ mov(eax, 13); 427 __ pop(esi); 428 __ pop(edi); 429 __ pop(edx); 430 __ pop(ecx); 431 __ pop(ebx); 432 __ ret(0); 433 434 CodeDesc desc; 435 assm.GetCode(&desc); 436 Handle<Code> code = isolate->factory()->NewCode( 437 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 438 CHECK(code->IsCode()); 439 440 F0 f = FUNCTION_CAST<F0>(code->entry()); 441 int res = f(); 442 CHECK_EQ(42, res); 443} 444 445 446#ifdef __GNUC__ 447#define ELEMENT_COUNT 4 448 449void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) { 450 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 451 HandleScope scope(isolate); 452 453 CHECK(args[0]->IsArray()); 454 v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]); 455 CHECK_EQ(ELEMENT_COUNT, vec->Length()); 456 457 v8::internal::byte buffer[256]; 458 Assembler assm(isolate, buffer, sizeof buffer); 459 460 // Remove return address from the stack for fix stack frame alignment. 461 __ pop(ecx); 462 463 // Store input vector on the stack. 464 for (int i = 0; i < ELEMENT_COUNT; ++i) { 465 __ push(Immediate(vec->Get(i)->Int32Value())); 466 } 467 468 // Read vector into a xmm register. 469 __ pxor(xmm0, xmm0); 470 __ movdqa(xmm0, Operand(esp, 0)); 471 // Create mask and store it in the return register. 472 __ movmskps(eax, xmm0); 473 474 // Remove unused data from the stack. 475 __ add(esp, Immediate(ELEMENT_COUNT * sizeof(int32_t))); 476 // Restore return address. 477 __ push(ecx); 478 479 __ ret(0); 480 481 CodeDesc desc; 482 assm.GetCode(&desc); 483 484 Handle<Code> code = isolate->factory()->NewCode( 485 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 486 487 F0 f = FUNCTION_CAST<F0>(code->entry()); 488 int res = f(); 489 args.GetReturnValue().Set(v8::Integer::New(CcTest::isolate(), res)); 490} 491 492 493TEST(StackAlignmentForSSE2) { 494 CcTest::InitializeVM(); 495 CHECK_EQ(0, v8::base::OS::ActivationFrameAlignment() % 16); 496 497 v8::Isolate* isolate = CcTest::isolate(); 498 v8::HandleScope handle_scope(isolate); 499 v8::Handle<v8::ObjectTemplate> global_template = 500 v8::ObjectTemplate::New(isolate); 501 global_template->Set(v8_str("do_sse2"), 502 v8::FunctionTemplate::New(isolate, DoSSE2)); 503 504 LocalContext env(NULL, global_template); 505 CompileRun( 506 "function foo(vec) {" 507 " return do_sse2(vec);" 508 "}"); 509 510 v8::Local<v8::Object> global_object = env->Global(); 511 v8::Local<v8::Function> foo = 512 v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo"))); 513 514 int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 }; 515 v8::Local<v8::Array> v8_vec = v8::Array::New(isolate, ELEMENT_COUNT); 516 for (int i = 0; i < ELEMENT_COUNT; i++) { 517 v8_vec->Set(i, v8_num(vec[i])); 518 } 519 520 v8::Local<v8::Value> args[] = { v8_vec }; 521 v8::Local<v8::Value> result = foo->Call(global_object, 1, args); 522 523 // The mask should be 0b1000. 524 CHECK_EQ(8, result->Int32Value()); 525} 526 527#undef ELEMENT_COUNT 528#endif // __GNUC__ 529 530 531TEST(AssemblerIa32Extractps) { 532 CcTest::InitializeVM(); 533 if (!CpuFeatures::IsSupported(SSE4_1)) return; 534 535 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 536 HandleScope scope(isolate); 537 v8::internal::byte buffer[256]; 538 MacroAssembler assm(isolate, buffer, sizeof buffer); 539 { CpuFeatureScope fscope41(&assm, SSE4_1); 540 __ movsd(xmm1, Operand(esp, 4)); 541 __ extractps(eax, xmm1, 0x1); 542 __ ret(0); 543 } 544 545 CodeDesc desc; 546 assm.GetCode(&desc); 547 Handle<Code> code = isolate->factory()->NewCode( 548 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 549#ifdef OBJECT_PRINT 550 OFStream os(stdout); 551 code->Print(os); 552#endif 553 554 F4 f = FUNCTION_CAST<F4>(code->entry()); 555 uint64_t value1 = V8_2PART_UINT64_C(0x12345678, 87654321); 556 CHECK_EQ(0x12345678, f(uint64_to_double(value1))); 557 uint64_t value2 = V8_2PART_UINT64_C(0x87654321, 12345678); 558 CHECK_EQ(0x87654321, f(uint64_to_double(value2))); 559} 560 561 562typedef int (*F8)(float x, float y); 563TEST(AssemblerIa32SSE) { 564 CcTest::InitializeVM(); 565 566 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); 567 HandleScope scope(isolate); 568 v8::internal::byte buffer[256]; 569 MacroAssembler assm(isolate, buffer, sizeof buffer); 570 { 571 __ movss(xmm0, Operand(esp, kPointerSize)); 572 __ movss(xmm1, Operand(esp, 2 * kPointerSize)); 573 __ shufps(xmm0, xmm0, 0x0); 574 __ shufps(xmm1, xmm1, 0x0); 575 __ movaps(xmm2, xmm1); 576 __ addps(xmm2, xmm0); 577 __ mulps(xmm2, xmm1); 578 __ subps(xmm2, xmm0); 579 __ divps(xmm2, xmm1); 580 __ cvttss2si(eax, xmm2); 581 __ ret(0); 582 } 583 584 CodeDesc desc; 585 assm.GetCode(&desc); 586 Handle<Code> code = isolate->factory()->NewCode( 587 desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); 588#ifdef OBJECT_PRINT 589 OFStream os(stdout); 590 code->Print(os); 591#endif 592 593 F8 f = FUNCTION_CAST<F8>(code->entry()); 594 CHECK_EQ(2, f(1.0, 2.0)); 595} 596 597 598#undef __ 599