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 38namespace i = v8::internal; 39using i::Address; 40using i::Assembler; 41using i::CodeDesc; 42using i::Condition; 43using i::FUNCTION_CAST; 44using i::HandleScope; 45using i::Immediate; 46using i::Isolate; 47using i::Label; 48using i::MacroAssembler; 49using i::OS; 50using i::Operand; 51using i::RelocInfo; 52using i::Representation; 53using i::Smi; 54using i::SmiIndex; 55using i::byte; 56using i::carry; 57using i::greater; 58using i::greater_equal; 59using i::kIntSize; 60using i::kPointerSize; 61using i::kSmiTagMask; 62using i::kSmiValueSize; 63using i::less_equal; 64using i::negative; 65using i::not_carry; 66using i::not_equal; 67using i::equal; 68using i::not_zero; 69using i::positive; 70using i::r11; 71using i::r13; 72using i::r14; 73using i::r15; 74using i::r8; 75using i::r9; 76using i::rax; 77using i::rbp; 78using i::rbx; 79using i::rcx; 80using i::rdi; 81using i::rdx; 82using i::rsi; 83using i::rsp; 84using i::times_pointer_size; 85 86// Test the x64 assembler by compiling some simple functions into 87// a buffer and executing them. These tests do not initialize the 88// V8 library, create a context, or use any V8 objects. 89// The AMD64 calling convention is used, with the first five arguments 90// in RSI, RDI, RDX, RCX, R8, and R9, and floating point arguments in 91// the XMM registers. The return value is in RAX. 92// This calling convention is used on Linux, with GCC, and on Mac OS, 93// with GCC. A different convention is used on 64-bit windows. 94 95typedef int (*F0)(); 96 97#define __ masm-> 98 99 100static void EntryCode(MacroAssembler* masm) { 101 // Smi constant register is callee save. 102 __ push(i::kSmiConstantRegister); 103 __ push(i::kRootRegister); 104 __ InitializeSmiConstantRegister(); 105 __ InitializeRootRegister(); 106} 107 108 109static void ExitCode(MacroAssembler* masm) { 110 // Return -1 if kSmiConstantRegister was clobbered during the test. 111 __ Move(rdx, Smi::FromInt(1)); 112 __ cmpq(rdx, i::kSmiConstantRegister); 113 __ movq(rdx, Immediate(-1)); 114 __ cmovq(not_equal, rax, rdx); 115 __ pop(i::kRootRegister); 116 __ pop(i::kSmiConstantRegister); 117} 118 119 120TEST(Smi) { 121 // Check that C++ Smi operations work as expected. 122 int64_t test_numbers[] = { 123 0, 1, -1, 127, 128, -128, -129, 255, 256, -256, -257, 124 Smi::kMaxValue, static_cast<int64_t>(Smi::kMaxValue) + 1, 125 Smi::kMinValue, static_cast<int64_t>(Smi::kMinValue) - 1 126 }; 127 int test_number_count = 15; 128 for (int i = 0; i < test_number_count; i++) { 129 int64_t number = test_numbers[i]; 130 bool is_valid = Smi::IsValid(number); 131 bool is_in_range = number >= Smi::kMinValue && number <= Smi::kMaxValue; 132 CHECK_EQ(is_in_range, is_valid); 133 if (is_valid) { 134 Smi* smi_from_intptr = Smi::FromIntptr(number); 135 if (static_cast<int>(number) == number) { // Is a 32-bit int. 136 Smi* smi_from_int = Smi::FromInt(static_cast<int32_t>(number)); 137 CHECK_EQ(smi_from_int, smi_from_intptr); 138 } 139 int64_t smi_value = smi_from_intptr->value(); 140 CHECK_EQ(number, smi_value); 141 } 142 } 143} 144 145 146static void TestMoveSmi(MacroAssembler* masm, Label* exit, int id, Smi* value) { 147 __ movl(rax, Immediate(id)); 148 __ Move(rcx, value); 149 __ Set(rdx, reinterpret_cast<intptr_t>(value)); 150 __ cmpq(rcx, rdx); 151 __ j(not_equal, exit); 152} 153 154 155// Test that we can move a Smi value literally into a register. 156TEST(SmiMove) { 157 i::V8::Initialize(NULL); 158 // Allocate an executable page of memory. 159 size_t actual_size; 160 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 161 &actual_size, 162 true)); 163 CHECK(buffer); 164 Isolate* isolate = CcTest::i_isolate(); 165 HandleScope handles(isolate); 166 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 167 MacroAssembler* masm = &assembler; // Create a pointer for the __ macro. 168 EntryCode(masm); 169 Label exit; 170 171 TestMoveSmi(masm, &exit, 1, Smi::FromInt(0)); 172 TestMoveSmi(masm, &exit, 2, Smi::FromInt(127)); 173 TestMoveSmi(masm, &exit, 3, Smi::FromInt(128)); 174 TestMoveSmi(masm, &exit, 4, Smi::FromInt(255)); 175 TestMoveSmi(masm, &exit, 5, Smi::FromInt(256)); 176 TestMoveSmi(masm, &exit, 6, Smi::FromInt(Smi::kMaxValue)); 177 TestMoveSmi(masm, &exit, 7, Smi::FromInt(-1)); 178 TestMoveSmi(masm, &exit, 8, Smi::FromInt(-128)); 179 TestMoveSmi(masm, &exit, 9, Smi::FromInt(-129)); 180 TestMoveSmi(masm, &exit, 10, Smi::FromInt(-256)); 181 TestMoveSmi(masm, &exit, 11, Smi::FromInt(-257)); 182 TestMoveSmi(masm, &exit, 12, Smi::FromInt(Smi::kMinValue)); 183 184 __ xor_(rax, rax); // Success. 185 __ bind(&exit); 186 ExitCode(masm); 187 __ ret(0); 188 189 CodeDesc desc; 190 masm->GetCode(&desc); 191 // Call the function from C++. 192 int result = FUNCTION_CAST<F0>(buffer)(); 193 CHECK_EQ(0, result); 194} 195 196 197void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) { 198 __ Move(rcx, Smi::FromInt(x)); 199 __ movq(r8, rcx); 200 __ Move(rdx, Smi::FromInt(y)); 201 __ movq(r9, rdx); 202 __ SmiCompare(rcx, rdx); 203 if (x < y) { 204 __ movl(rax, Immediate(id + 1)); 205 __ j(greater_equal, exit); 206 } else if (x > y) { 207 __ movl(rax, Immediate(id + 2)); 208 __ j(less_equal, exit); 209 } else { 210 ASSERT_EQ(x, y); 211 __ movl(rax, Immediate(id + 3)); 212 __ j(not_equal, exit); 213 } 214 __ movl(rax, Immediate(id + 4)); 215 __ cmpq(rcx, r8); 216 __ j(not_equal, exit); 217 __ incq(rax); 218 __ cmpq(rdx, r9); 219 __ j(not_equal, exit); 220 221 if (x != y) { 222 __ SmiCompare(rdx, rcx); 223 if (y < x) { 224 __ movl(rax, Immediate(id + 9)); 225 __ j(greater_equal, exit); 226 } else { 227 ASSERT(y > x); 228 __ movl(rax, Immediate(id + 10)); 229 __ j(less_equal, exit); 230 } 231 } else { 232 __ cmpq(rcx, rcx); 233 __ movl(rax, Immediate(id + 11)); 234 __ j(not_equal, exit); 235 __ incq(rax); 236 __ cmpq(rcx, r8); 237 __ j(not_equal, exit); 238 } 239} 240 241 242// Test that we can compare smis for equality (and more). 243TEST(SmiCompare) { 244 i::V8::Initialize(NULL); 245 // Allocate an executable page of memory. 246 size_t actual_size; 247 byte* buffer = 248 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, 249 &actual_size, 250 true)); 251 CHECK(buffer); 252 Isolate* isolate = CcTest::i_isolate(); 253 HandleScope handles(isolate); 254 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 255 256 MacroAssembler* masm = &assembler; 257 EntryCode(masm); 258 Label exit; 259 260 TestSmiCompare(masm, &exit, 0x10, 0, 0); 261 TestSmiCompare(masm, &exit, 0x20, 0, 1); 262 TestSmiCompare(masm, &exit, 0x30, 1, 0); 263 TestSmiCompare(masm, &exit, 0x40, 1, 1); 264 TestSmiCompare(masm, &exit, 0x50, 0, -1); 265 TestSmiCompare(masm, &exit, 0x60, -1, 0); 266 TestSmiCompare(masm, &exit, 0x70, -1, -1); 267 TestSmiCompare(masm, &exit, 0x80, 0, Smi::kMinValue); 268 TestSmiCompare(masm, &exit, 0x90, Smi::kMinValue, 0); 269 TestSmiCompare(masm, &exit, 0xA0, 0, Smi::kMaxValue); 270 TestSmiCompare(masm, &exit, 0xB0, Smi::kMaxValue, 0); 271 TestSmiCompare(masm, &exit, 0xC0, -1, Smi::kMinValue); 272 TestSmiCompare(masm, &exit, 0xD0, Smi::kMinValue, -1); 273 TestSmiCompare(masm, &exit, 0xE0, -1, Smi::kMaxValue); 274 TestSmiCompare(masm, &exit, 0xF0, Smi::kMaxValue, -1); 275 TestSmiCompare(masm, &exit, 0x100, Smi::kMinValue, Smi::kMinValue); 276 TestSmiCompare(masm, &exit, 0x110, Smi::kMinValue, Smi::kMaxValue); 277 TestSmiCompare(masm, &exit, 0x120, Smi::kMaxValue, Smi::kMinValue); 278 TestSmiCompare(masm, &exit, 0x130, Smi::kMaxValue, Smi::kMaxValue); 279 280 __ xor_(rax, rax); // Success. 281 __ bind(&exit); 282 ExitCode(masm); 283 __ ret(0); 284 285 CodeDesc desc; 286 masm->GetCode(&desc); 287 // Call the function from C++. 288 int result = FUNCTION_CAST<F0>(buffer)(); 289 CHECK_EQ(0, result); 290} 291 292 293 294TEST(Integer32ToSmi) { 295 i::V8::Initialize(NULL); 296 // Allocate an executable page of memory. 297 size_t actual_size; 298 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 299 &actual_size, 300 true)); 301 CHECK(buffer); 302 Isolate* isolate = CcTest::i_isolate(); 303 HandleScope handles(isolate); 304 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 305 306 MacroAssembler* masm = &assembler; 307 EntryCode(masm); 308 Label exit; 309 310 __ movq(rax, Immediate(1)); // Test number. 311 __ movl(rcx, Immediate(0)); 312 __ Integer32ToSmi(rcx, rcx); 313 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0))); 314 __ cmpq(rcx, rdx); 315 __ j(not_equal, &exit); 316 317 __ movq(rax, Immediate(2)); // Test number. 318 __ movl(rcx, Immediate(1024)); 319 __ Integer32ToSmi(rcx, rcx); 320 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024))); 321 __ cmpq(rcx, rdx); 322 __ j(not_equal, &exit); 323 324 __ movq(rax, Immediate(3)); // Test number. 325 __ movl(rcx, Immediate(-1)); 326 __ Integer32ToSmi(rcx, rcx); 327 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1))); 328 __ cmpq(rcx, rdx); 329 __ j(not_equal, &exit); 330 331 __ movq(rax, Immediate(4)); // Test number. 332 __ movl(rcx, Immediate(Smi::kMaxValue)); 333 __ Integer32ToSmi(rcx, rcx); 334 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue))); 335 __ cmpq(rcx, rdx); 336 __ j(not_equal, &exit); 337 338 __ movq(rax, Immediate(5)); // Test number. 339 __ movl(rcx, Immediate(Smi::kMinValue)); 340 __ Integer32ToSmi(rcx, rcx); 341 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue))); 342 __ cmpq(rcx, rdx); 343 __ j(not_equal, &exit); 344 345 // Different target register. 346 347 __ movq(rax, Immediate(6)); // Test number. 348 __ movl(rcx, Immediate(0)); 349 __ Integer32ToSmi(r8, rcx); 350 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0))); 351 __ cmpq(r8, rdx); 352 __ j(not_equal, &exit); 353 354 __ movq(rax, Immediate(7)); // Test number. 355 __ movl(rcx, Immediate(1024)); 356 __ Integer32ToSmi(r8, rcx); 357 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024))); 358 __ cmpq(r8, rdx); 359 __ j(not_equal, &exit); 360 361 __ movq(rax, Immediate(8)); // Test number. 362 __ movl(rcx, Immediate(-1)); 363 __ Integer32ToSmi(r8, rcx); 364 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1))); 365 __ cmpq(r8, rdx); 366 __ j(not_equal, &exit); 367 368 __ movq(rax, Immediate(9)); // Test number. 369 __ movl(rcx, Immediate(Smi::kMaxValue)); 370 __ Integer32ToSmi(r8, rcx); 371 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue))); 372 __ cmpq(r8, rdx); 373 __ j(not_equal, &exit); 374 375 __ movq(rax, Immediate(10)); // Test number. 376 __ movl(rcx, Immediate(Smi::kMinValue)); 377 __ Integer32ToSmi(r8, rcx); 378 __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue))); 379 __ cmpq(r8, rdx); 380 __ j(not_equal, &exit); 381 382 383 __ xor_(rax, rax); // Success. 384 __ bind(&exit); 385 ExitCode(masm); 386 __ ret(0); 387 388 CodeDesc desc; 389 masm->GetCode(&desc); 390 // Call the function from C++. 391 int result = FUNCTION_CAST<F0>(buffer)(); 392 CHECK_EQ(0, result); 393} 394 395 396void TestI64PlusConstantToSmi(MacroAssembler* masm, 397 Label* exit, 398 int id, 399 int64_t x, 400 int y) { 401 int64_t result = x + y; 402 ASSERT(Smi::IsValid(result)); 403 __ movl(rax, Immediate(id)); 404 __ Move(r8, Smi::FromInt(static_cast<int>(result))); 405 __ movq(rcx, x); 406 __ movq(r11, rcx); 407 __ Integer64PlusConstantToSmi(rdx, rcx, y); 408 __ cmpq(rdx, r8); 409 __ j(not_equal, exit); 410 411 __ incq(rax); 412 __ cmpq(r11, rcx); 413 __ j(not_equal, exit); 414 415 __ incq(rax); 416 __ Integer64PlusConstantToSmi(rcx, rcx, y); 417 __ cmpq(rcx, r8); 418 __ j(not_equal, exit); 419} 420 421 422TEST(Integer64PlusConstantToSmi) { 423 i::V8::Initialize(NULL); 424 // Allocate an executable page of memory. 425 size_t actual_size; 426 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 427 &actual_size, 428 true)); 429 CHECK(buffer); 430 Isolate* isolate = CcTest::i_isolate(); 431 HandleScope handles(isolate); 432 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 433 434 MacroAssembler* masm = &assembler; 435 EntryCode(masm); 436 Label exit; 437 438 int64_t twice_max = static_cast<int64_t>(Smi::kMaxValue) * 2; 439 440 TestI64PlusConstantToSmi(masm, &exit, 0x10, 0, 0); 441 TestI64PlusConstantToSmi(masm, &exit, 0x20, 0, 1); 442 TestI64PlusConstantToSmi(masm, &exit, 0x30, 1, 0); 443 TestI64PlusConstantToSmi(masm, &exit, 0x40, Smi::kMaxValue - 5, 5); 444 TestI64PlusConstantToSmi(masm, &exit, 0x50, Smi::kMinValue + 5, 5); 445 TestI64PlusConstantToSmi(masm, &exit, 0x60, twice_max, -Smi::kMaxValue); 446 TestI64PlusConstantToSmi(masm, &exit, 0x70, -twice_max, Smi::kMaxValue); 447 TestI64PlusConstantToSmi(masm, &exit, 0x80, 0, Smi::kMinValue); 448 TestI64PlusConstantToSmi(masm, &exit, 0x90, 0, Smi::kMaxValue); 449 TestI64PlusConstantToSmi(masm, &exit, 0xA0, Smi::kMinValue, 0); 450 TestI64PlusConstantToSmi(masm, &exit, 0xB0, Smi::kMaxValue, 0); 451 TestI64PlusConstantToSmi(masm, &exit, 0xC0, twice_max, Smi::kMinValue); 452 453 __ xor_(rax, rax); // Success. 454 __ bind(&exit); 455 ExitCode(masm); 456 __ ret(0); 457 458 CodeDesc desc; 459 masm->GetCode(&desc); 460 // Call the function from C++. 461 int result = FUNCTION_CAST<F0>(buffer)(); 462 CHECK_EQ(0, result); 463} 464 465 466TEST(SmiCheck) { 467 i::V8::Initialize(NULL); 468 // Allocate an executable page of memory. 469 size_t actual_size; 470 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 471 &actual_size, 472 true)); 473 CHECK(buffer); 474 Isolate* isolate = CcTest::i_isolate(); 475 HandleScope handles(isolate); 476 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 477 478 MacroAssembler* masm = &assembler; 479 EntryCode(masm); 480 Label exit; 481 Condition cond; 482 483 __ movl(rax, Immediate(1)); // Test number. 484 485 // CheckSmi 486 487 __ movl(rcx, Immediate(0)); 488 __ Integer32ToSmi(rcx, rcx); 489 cond = masm->CheckSmi(rcx); 490 __ j(NegateCondition(cond), &exit); 491 492 __ incq(rax); 493 __ xor_(rcx, Immediate(kSmiTagMask)); 494 cond = masm->CheckSmi(rcx); 495 __ j(cond, &exit); 496 497 __ incq(rax); 498 __ movl(rcx, Immediate(-1)); 499 __ Integer32ToSmi(rcx, rcx); 500 cond = masm->CheckSmi(rcx); 501 __ j(NegateCondition(cond), &exit); 502 503 __ incq(rax); 504 __ xor_(rcx, Immediate(kSmiTagMask)); 505 cond = masm->CheckSmi(rcx); 506 __ j(cond, &exit); 507 508 __ incq(rax); 509 __ movl(rcx, Immediate(Smi::kMaxValue)); 510 __ Integer32ToSmi(rcx, rcx); 511 cond = masm->CheckSmi(rcx); 512 __ j(NegateCondition(cond), &exit); 513 514 __ incq(rax); 515 __ xor_(rcx, Immediate(kSmiTagMask)); 516 cond = masm->CheckSmi(rcx); 517 __ j(cond, &exit); 518 519 __ incq(rax); 520 __ movl(rcx, Immediate(Smi::kMinValue)); 521 __ Integer32ToSmi(rcx, rcx); 522 cond = masm->CheckSmi(rcx); 523 __ j(NegateCondition(cond), &exit); 524 525 __ incq(rax); 526 __ xor_(rcx, Immediate(kSmiTagMask)); 527 cond = masm->CheckSmi(rcx); 528 __ j(cond, &exit); 529 530 // CheckPositiveSmi 531 532 __ incq(rax); 533 __ movl(rcx, Immediate(0)); 534 __ Integer32ToSmi(rcx, rcx); 535 cond = masm->CheckNonNegativeSmi(rcx); 536 __ j(NegateCondition(cond), &exit); 537 538 __ incq(rax); 539 __ xor_(rcx, Immediate(kSmiTagMask)); 540 cond = masm->CheckNonNegativeSmi(rcx); // "zero" non-smi. 541 __ j(cond, &exit); 542 543 __ incq(rax); 544 __ movq(rcx, Immediate(-1)); 545 __ Integer32ToSmi(rcx, rcx); 546 cond = masm->CheckNonNegativeSmi(rcx); // Negative smis are not positive. 547 __ j(cond, &exit); 548 549 __ incq(rax); 550 __ movq(rcx, Immediate(Smi::kMinValue)); 551 __ Integer32ToSmi(rcx, rcx); 552 cond = masm->CheckNonNegativeSmi(rcx); // Most negative smi is not positive. 553 __ j(cond, &exit); 554 555 __ incq(rax); 556 __ xor_(rcx, Immediate(kSmiTagMask)); 557 cond = masm->CheckNonNegativeSmi(rcx); // "Negative" non-smi. 558 __ j(cond, &exit); 559 560 __ incq(rax); 561 __ movq(rcx, Immediate(Smi::kMaxValue)); 562 __ Integer32ToSmi(rcx, rcx); 563 cond = masm->CheckNonNegativeSmi(rcx); // Most positive smi is positive. 564 __ j(NegateCondition(cond), &exit); 565 566 __ incq(rax); 567 __ xor_(rcx, Immediate(kSmiTagMask)); 568 cond = masm->CheckNonNegativeSmi(rcx); // "Positive" non-smi. 569 __ j(cond, &exit); 570 571 // CheckIsMinSmi 572 573 __ incq(rax); 574 __ movq(rcx, Immediate(Smi::kMaxValue)); 575 __ Integer32ToSmi(rcx, rcx); 576 cond = masm->CheckIsMinSmi(rcx); 577 __ j(cond, &exit); 578 579 __ incq(rax); 580 __ movq(rcx, Immediate(0)); 581 __ Integer32ToSmi(rcx, rcx); 582 cond = masm->CheckIsMinSmi(rcx); 583 __ j(cond, &exit); 584 585 __ incq(rax); 586 __ movq(rcx, Immediate(Smi::kMinValue)); 587 __ Integer32ToSmi(rcx, rcx); 588 cond = masm->CheckIsMinSmi(rcx); 589 __ j(NegateCondition(cond), &exit); 590 591 __ incq(rax); 592 __ movq(rcx, Immediate(Smi::kMinValue + 1)); 593 __ Integer32ToSmi(rcx, rcx); 594 cond = masm->CheckIsMinSmi(rcx); 595 __ j(cond, &exit); 596 597 // CheckBothSmi 598 599 __ incq(rax); 600 __ movq(rcx, Immediate(Smi::kMaxValue)); 601 __ Integer32ToSmi(rcx, rcx); 602 __ movq(rdx, Immediate(Smi::kMinValue)); 603 __ Integer32ToSmi(rdx, rdx); 604 cond = masm->CheckBothSmi(rcx, rdx); 605 __ j(NegateCondition(cond), &exit); 606 607 __ incq(rax); 608 __ xor_(rcx, Immediate(kSmiTagMask)); 609 cond = masm->CheckBothSmi(rcx, rdx); 610 __ j(cond, &exit); 611 612 __ incq(rax); 613 __ xor_(rdx, Immediate(kSmiTagMask)); 614 cond = masm->CheckBothSmi(rcx, rdx); 615 __ j(cond, &exit); 616 617 __ incq(rax); 618 __ xor_(rcx, Immediate(kSmiTagMask)); 619 cond = masm->CheckBothSmi(rcx, rdx); 620 __ j(cond, &exit); 621 622 __ incq(rax); 623 cond = masm->CheckBothSmi(rcx, rcx); 624 __ j(NegateCondition(cond), &exit); 625 626 __ incq(rax); 627 cond = masm->CheckBothSmi(rdx, rdx); 628 __ j(cond, &exit); 629 630 // CheckInteger32ValidSmiValue 631 __ incq(rax); 632 __ movq(rcx, Immediate(0)); 633 cond = masm->CheckInteger32ValidSmiValue(rax); 634 __ j(NegateCondition(cond), &exit); 635 636 __ incq(rax); 637 __ movq(rcx, Immediate(-1)); 638 cond = masm->CheckInteger32ValidSmiValue(rax); 639 __ j(NegateCondition(cond), &exit); 640 641 __ incq(rax); 642 __ movq(rcx, Immediate(Smi::kMaxValue)); 643 cond = masm->CheckInteger32ValidSmiValue(rax); 644 __ j(NegateCondition(cond), &exit); 645 646 __ incq(rax); 647 __ movq(rcx, Immediate(Smi::kMinValue)); 648 cond = masm->CheckInteger32ValidSmiValue(rax); 649 __ j(NegateCondition(cond), &exit); 650 651 // Success 652 __ xor_(rax, rax); 653 654 __ bind(&exit); 655 ExitCode(masm); 656 __ ret(0); 657 658 CodeDesc desc; 659 masm->GetCode(&desc); 660 // Call the function from C++. 661 int result = FUNCTION_CAST<F0>(buffer)(); 662 CHECK_EQ(0, result); 663} 664 665 666 667void TestSmiNeg(MacroAssembler* masm, Label* exit, int id, int x) { 668 __ Move(rcx, Smi::FromInt(x)); 669 __ movq(r11, rcx); 670 if (x == Smi::kMinValue || x == 0) { 671 // Negation fails. 672 __ movl(rax, Immediate(id + 8)); 673 __ SmiNeg(r9, rcx, exit); 674 675 __ incq(rax); 676 __ cmpq(r11, rcx); 677 __ j(not_equal, exit); 678 679 __ incq(rax); 680 __ SmiNeg(rcx, rcx, exit); 681 682 __ incq(rax); 683 __ cmpq(r11, rcx); 684 __ j(not_equal, exit); 685 } else { 686 Label smi_ok, smi_ok2; 687 int result = -x; 688 __ movl(rax, Immediate(id)); 689 __ Move(r8, Smi::FromInt(result)); 690 691 __ SmiNeg(r9, rcx, &smi_ok); 692 __ jmp(exit); 693 __ bind(&smi_ok); 694 __ incq(rax); 695 __ cmpq(r9, r8); 696 __ j(not_equal, exit); 697 698 __ incq(rax); 699 __ cmpq(r11, rcx); 700 __ j(not_equal, exit); 701 702 __ incq(rax); 703 __ SmiNeg(rcx, rcx, &smi_ok2); 704 __ jmp(exit); 705 __ bind(&smi_ok2); 706 __ incq(rax); 707 __ cmpq(rcx, r8); 708 __ j(not_equal, exit); 709 } 710} 711 712 713TEST(SmiNeg) { 714 i::V8::Initialize(NULL); 715 // Allocate an executable page of memory. 716 size_t actual_size; 717 byte* buffer = 718 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 719 &actual_size, 720 true)); 721 CHECK(buffer); 722 Isolate* isolate = CcTest::i_isolate(); 723 HandleScope handles(isolate); 724 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 725 726 MacroAssembler* masm = &assembler; 727 EntryCode(masm); 728 Label exit; 729 730 TestSmiNeg(masm, &exit, 0x10, 0); 731 TestSmiNeg(masm, &exit, 0x20, 1); 732 TestSmiNeg(masm, &exit, 0x30, -1); 733 TestSmiNeg(masm, &exit, 0x40, 127); 734 TestSmiNeg(masm, &exit, 0x50, 65535); 735 TestSmiNeg(masm, &exit, 0x60, Smi::kMinValue); 736 TestSmiNeg(masm, &exit, 0x70, Smi::kMaxValue); 737 TestSmiNeg(masm, &exit, 0x80, -Smi::kMaxValue); 738 739 __ xor_(rax, rax); // Success. 740 __ bind(&exit); 741 ExitCode(masm); 742 __ ret(0); 743 744 CodeDesc desc; 745 masm->GetCode(&desc); 746 // Call the function from C++. 747 int result = FUNCTION_CAST<F0>(buffer)(); 748 CHECK_EQ(0, result); 749} 750 751 752static void SmiAddTest(MacroAssembler* masm, 753 Label* exit, 754 int id, 755 int first, 756 int second) { 757 __ movl(rcx, Immediate(first)); 758 __ Integer32ToSmi(rcx, rcx); 759 __ movl(rdx, Immediate(second)); 760 __ Integer32ToSmi(rdx, rdx); 761 __ movl(r8, Immediate(first + second)); 762 __ Integer32ToSmi(r8, r8); 763 764 __ movl(rax, Immediate(id)); // Test number. 765 __ SmiAdd(r9, rcx, rdx, exit); 766 __ cmpq(r9, r8); 767 __ j(not_equal, exit); 768 769 __ incq(rax); 770 __ SmiAdd(rcx, rcx, rdx, exit); 771 __ cmpq(rcx, r8); 772 __ j(not_equal, exit); 773 774 __ movl(rcx, Immediate(first)); 775 __ Integer32ToSmi(rcx, rcx); 776 777 __ incq(rax); 778 __ SmiAddConstant(r9, rcx, Smi::FromInt(second)); 779 __ cmpq(r9, r8); 780 __ j(not_equal, exit); 781 782 __ SmiAddConstant(rcx, rcx, Smi::FromInt(second)); 783 __ cmpq(rcx, r8); 784 __ j(not_equal, exit); 785 786 __ movl(rcx, Immediate(first)); 787 __ Integer32ToSmi(rcx, rcx); 788 789 i::SmiOperationExecutionMode mode; 790 mode.Add(i::PRESERVE_SOURCE_REGISTER); 791 mode.Add(i::BAILOUT_ON_OVERFLOW); 792 __ incq(rax); 793 __ SmiAddConstant(r9, rcx, Smi::FromInt(second), mode, exit); 794 __ cmpq(r9, r8); 795 __ j(not_equal, exit); 796 797 __ incq(rax); 798 __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), mode, exit); 799 __ cmpq(rcx, r8); 800 __ j(not_equal, exit); 801 802 __ movl(rcx, Immediate(first)); 803 __ Integer32ToSmi(rcx, rcx); 804 805 mode.RemoveAll(); 806 mode.Add(i::PRESERVE_SOURCE_REGISTER); 807 mode.Add(i::BAILOUT_ON_NO_OVERFLOW); 808 Label done; 809 __ incq(rax); 810 __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), mode, &done); 811 __ jmp(exit); 812 __ bind(&done); 813 __ cmpq(rcx, r8); 814 __ j(not_equal, exit); 815} 816 817 818static void SmiAddOverflowTest(MacroAssembler* masm, 819 Label* exit, 820 int id, 821 int x) { 822 // Adds a Smi to x so that the addition overflows. 823 ASSERT(x != 0); // Can't overflow by adding a Smi. 824 int y_max = (x > 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue - x - 1); 825 int y_min = (x > 0) ? (Smi::kMaxValue - x + 1) : (Smi::kMinValue + 0); 826 827 __ movl(rax, Immediate(id)); 828 __ Move(rcx, Smi::FromInt(x)); 829 __ movq(r11, rcx); // Store original Smi value of x in r11. 830 __ Move(rdx, Smi::FromInt(y_min)); 831 { 832 Label overflow_ok; 833 __ SmiAdd(r9, rcx, rdx, &overflow_ok); 834 __ jmp(exit); 835 __ bind(&overflow_ok); 836 __ incq(rax); 837 __ cmpq(rcx, r11); 838 __ j(not_equal, exit); 839 } 840 841 { 842 Label overflow_ok; 843 __ incq(rax); 844 __ SmiAdd(rcx, rcx, rdx, &overflow_ok); 845 __ jmp(exit); 846 __ bind(&overflow_ok); 847 __ incq(rax); 848 __ cmpq(rcx, r11); 849 __ j(not_equal, exit); 850 } 851 852 i::SmiOperationExecutionMode mode; 853 mode.Add(i::PRESERVE_SOURCE_REGISTER); 854 mode.Add(i::BAILOUT_ON_OVERFLOW); 855 __ movq(rcx, r11); 856 { 857 Label overflow_ok; 858 __ incq(rax); 859 __ SmiAddConstant(r9, rcx, Smi::FromInt(y_min), mode, &overflow_ok); 860 __ jmp(exit); 861 __ bind(&overflow_ok); 862 __ incq(rax); 863 __ cmpq(rcx, r11); 864 __ j(not_equal, exit); 865 } 866 867 { 868 Label overflow_ok; 869 __ incq(rax); 870 __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_min), mode, &overflow_ok); 871 __ jmp(exit); 872 __ bind(&overflow_ok); 873 __ incq(rax); 874 __ cmpq(rcx, r11); 875 __ j(not_equal, exit); 876 } 877 878 __ Move(rdx, Smi::FromInt(y_max)); 879 880 { 881 Label overflow_ok; 882 __ incq(rax); 883 __ SmiAdd(r9, rcx, rdx, &overflow_ok); 884 __ jmp(exit); 885 __ bind(&overflow_ok); 886 __ incq(rax); 887 __ cmpq(rcx, r11); 888 __ j(not_equal, exit); 889 } 890 891 { 892 Label overflow_ok; 893 __ incq(rax); 894 __ SmiAdd(rcx, rcx, rdx, &overflow_ok); 895 __ jmp(exit); 896 __ bind(&overflow_ok); 897 __ incq(rax); 898 __ cmpq(rcx, r11); 899 __ j(not_equal, exit); 900 } 901 902 __ movq(rcx, r11); 903 { 904 Label overflow_ok; 905 __ incq(rax); 906 __ SmiAddConstant(r9, rcx, Smi::FromInt(y_max), mode, &overflow_ok); 907 __ jmp(exit); 908 __ bind(&overflow_ok); 909 __ incq(rax); 910 __ cmpq(rcx, r11); 911 __ j(not_equal, exit); 912 } 913 914 mode.RemoveAll(); 915 mode.Add(i::BAILOUT_ON_OVERFLOW); 916 { 917 Label overflow_ok; 918 __ incq(rax); 919 __ SmiAddConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok); 920 __ jmp(exit); 921 __ bind(&overflow_ok); 922 __ incq(rax); 923 __ cmpq(rcx, r11); 924 __ j(equal, exit); 925 } 926} 927 928 929TEST(SmiAdd) { 930 i::V8::Initialize(NULL); 931 // Allocate an executable page of memory. 932 size_t actual_size; 933 byte* buffer = 934 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3, 935 &actual_size, 936 true)); 937 CHECK(buffer); 938 Isolate* isolate = CcTest::i_isolate(); 939 HandleScope handles(isolate); 940 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 941 942 MacroAssembler* masm = &assembler; 943 EntryCode(masm); 944 Label exit; 945 946 // No-overflow tests. 947 SmiAddTest(masm, &exit, 0x10, 1, 2); 948 SmiAddTest(masm, &exit, 0x20, 1, -2); 949 SmiAddTest(masm, &exit, 0x30, -1, 2); 950 SmiAddTest(masm, &exit, 0x40, -1, -2); 951 SmiAddTest(masm, &exit, 0x50, 0x1000, 0x2000); 952 SmiAddTest(masm, &exit, 0x60, Smi::kMinValue, 5); 953 SmiAddTest(masm, &exit, 0x70, Smi::kMaxValue, -5); 954 SmiAddTest(masm, &exit, 0x80, Smi::kMaxValue, Smi::kMinValue); 955 956 SmiAddOverflowTest(masm, &exit, 0x90, -1); 957 SmiAddOverflowTest(masm, &exit, 0xA0, 1); 958 SmiAddOverflowTest(masm, &exit, 0xB0, 1024); 959 SmiAddOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue); 960 SmiAddOverflowTest(masm, &exit, 0xD0, -2); 961 SmiAddOverflowTest(masm, &exit, 0xE0, -42000); 962 SmiAddOverflowTest(masm, &exit, 0xF0, Smi::kMinValue); 963 964 __ xor_(rax, rax); // Success. 965 __ bind(&exit); 966 ExitCode(masm); 967 __ ret(0); 968 969 CodeDesc desc; 970 masm->GetCode(&desc); 971 // Call the function from C++. 972 int result = FUNCTION_CAST<F0>(buffer)(); 973 CHECK_EQ(0, result); 974} 975 976 977static void SmiSubTest(MacroAssembler* masm, 978 Label* exit, 979 int id, 980 int first, 981 int second) { 982 __ Move(rcx, Smi::FromInt(first)); 983 __ Move(rdx, Smi::FromInt(second)); 984 __ Move(r8, Smi::FromInt(first - second)); 985 986 __ movl(rax, Immediate(id)); // Test 0. 987 __ SmiSub(r9, rcx, rdx, exit); 988 __ cmpq(r9, r8); 989 __ j(not_equal, exit); 990 991 __ incq(rax); // Test 1. 992 __ SmiSub(rcx, rcx, rdx, exit); 993 __ cmpq(rcx, r8); 994 __ j(not_equal, exit); 995 996 __ Move(rcx, Smi::FromInt(first)); 997 998 __ incq(rax); // Test 2. 999 __ SmiSubConstant(r9, rcx, Smi::FromInt(second)); 1000 __ cmpq(r9, r8); 1001 __ j(not_equal, exit); 1002 1003 __ incq(rax); // Test 3. 1004 __ SmiSubConstant(rcx, rcx, Smi::FromInt(second)); 1005 __ cmpq(rcx, r8); 1006 __ j(not_equal, exit); 1007 1008 i::SmiOperationExecutionMode mode; 1009 mode.Add(i::PRESERVE_SOURCE_REGISTER); 1010 mode.Add(i::BAILOUT_ON_OVERFLOW); 1011 __ Move(rcx, Smi::FromInt(first)); 1012 __ incq(rax); // Test 4. 1013 __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), mode, exit); 1014 __ cmpq(rcx, r8); 1015 __ j(not_equal, exit); 1016 1017 __ Move(rcx, Smi::FromInt(first)); 1018 __ incq(rax); // Test 5. 1019 __ SmiSubConstant(r9, rcx, Smi::FromInt(second), mode, exit); 1020 __ cmpq(r9, r8); 1021 __ j(not_equal, exit); 1022 1023 mode.RemoveAll(); 1024 mode.Add(i::PRESERVE_SOURCE_REGISTER); 1025 mode.Add(i::BAILOUT_ON_NO_OVERFLOW); 1026 __ Move(rcx, Smi::FromInt(first)); 1027 Label done; 1028 __ incq(rax); // Test 6. 1029 __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), mode, &done); 1030 __ jmp(exit); 1031 __ bind(&done); 1032 __ cmpq(rcx, r8); 1033 __ j(not_equal, exit); 1034} 1035 1036 1037static void SmiSubOverflowTest(MacroAssembler* masm, 1038 Label* exit, 1039 int id, 1040 int x) { 1041 // Subtracts a Smi from x so that the subtraction overflows. 1042 ASSERT(x != -1); // Can't overflow by subtracting a Smi. 1043 int y_max = (x < 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue + 0); 1044 int y_min = (x < 0) ? (Smi::kMaxValue + x + 2) : (Smi::kMinValue + x); 1045 1046 __ movl(rax, Immediate(id)); 1047 __ Move(rcx, Smi::FromInt(x)); 1048 __ movq(r11, rcx); // Store original Smi value of x in r11. 1049 __ Move(rdx, Smi::FromInt(y_min)); 1050 { 1051 Label overflow_ok; 1052 __ SmiSub(r9, rcx, rdx, &overflow_ok); 1053 __ jmp(exit); 1054 __ bind(&overflow_ok); 1055 __ incq(rax); 1056 __ cmpq(rcx, r11); 1057 __ j(not_equal, exit); 1058 } 1059 1060 { 1061 Label overflow_ok; 1062 __ incq(rax); 1063 __ SmiSub(rcx, rcx, rdx, &overflow_ok); 1064 __ jmp(exit); 1065 __ bind(&overflow_ok); 1066 __ incq(rax); 1067 __ cmpq(rcx, r11); 1068 __ j(not_equal, exit); 1069 } 1070 1071 i::SmiOperationExecutionMode mode; 1072 mode.Add(i::PRESERVE_SOURCE_REGISTER); 1073 mode.Add(i::BAILOUT_ON_OVERFLOW); 1074 1075 __ movq(rcx, r11); 1076 { 1077 Label overflow_ok; 1078 __ incq(rax); 1079 __ SmiSubConstant(r9, rcx, Smi::FromInt(y_min), mode, &overflow_ok); 1080 __ jmp(exit); 1081 __ bind(&overflow_ok); 1082 __ incq(rax); 1083 __ cmpq(rcx, r11); 1084 __ j(not_equal, exit); 1085 } 1086 1087 { 1088 Label overflow_ok; 1089 __ incq(rax); 1090 __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_min), mode, &overflow_ok); 1091 __ jmp(exit); 1092 __ bind(&overflow_ok); 1093 __ incq(rax); 1094 __ cmpq(rcx, r11); 1095 __ j(not_equal, exit); 1096 } 1097 1098 __ Move(rdx, Smi::FromInt(y_max)); 1099 1100 { 1101 Label overflow_ok; 1102 __ incq(rax); 1103 __ SmiSub(r9, rcx, rdx, &overflow_ok); 1104 __ jmp(exit); 1105 __ bind(&overflow_ok); 1106 __ incq(rax); 1107 __ cmpq(rcx, r11); 1108 __ j(not_equal, exit); 1109 } 1110 1111 { 1112 Label overflow_ok; 1113 __ incq(rax); 1114 __ SmiSub(rcx, rcx, rdx, &overflow_ok); 1115 __ jmp(exit); 1116 __ bind(&overflow_ok); 1117 __ incq(rax); 1118 __ cmpq(rcx, r11); 1119 __ j(not_equal, exit); 1120 } 1121 1122 __ movq(rcx, r11); 1123 { 1124 Label overflow_ok; 1125 __ incq(rax); 1126 __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok); 1127 __ jmp(exit); 1128 __ bind(&overflow_ok); 1129 __ incq(rax); 1130 __ cmpq(rcx, r11); 1131 __ j(not_equal, exit); 1132 } 1133 1134 mode.RemoveAll(); 1135 mode.Add(i::BAILOUT_ON_OVERFLOW); 1136 __ movq(rcx, r11); 1137 { 1138 Label overflow_ok; 1139 __ incq(rax); 1140 __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), mode, &overflow_ok); 1141 __ jmp(exit); 1142 __ bind(&overflow_ok); 1143 __ incq(rax); 1144 __ cmpq(rcx, r11); 1145 __ j(equal, exit); 1146 } 1147} 1148 1149 1150TEST(SmiSub) { 1151 i::V8::Initialize(NULL); 1152 // Allocate an executable page of memory. 1153 size_t actual_size; 1154 byte* buffer = 1155 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4, 1156 &actual_size, 1157 true)); 1158 CHECK(buffer); 1159 Isolate* isolate = CcTest::i_isolate(); 1160 HandleScope handles(isolate); 1161 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1162 1163 MacroAssembler* masm = &assembler; 1164 EntryCode(masm); 1165 Label exit; 1166 1167 SmiSubTest(masm, &exit, 0x10, 1, 2); 1168 SmiSubTest(masm, &exit, 0x20, 1, -2); 1169 SmiSubTest(masm, &exit, 0x30, -1, 2); 1170 SmiSubTest(masm, &exit, 0x40, -1, -2); 1171 SmiSubTest(masm, &exit, 0x50, 0x1000, 0x2000); 1172 SmiSubTest(masm, &exit, 0x60, Smi::kMinValue, -5); 1173 SmiSubTest(masm, &exit, 0x70, Smi::kMaxValue, 5); 1174 SmiSubTest(masm, &exit, 0x80, -Smi::kMaxValue, Smi::kMinValue); 1175 SmiSubTest(masm, &exit, 0x90, 0, Smi::kMaxValue); 1176 1177 SmiSubOverflowTest(masm, &exit, 0xA0, 1); 1178 SmiSubOverflowTest(masm, &exit, 0xB0, 1024); 1179 SmiSubOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue); 1180 SmiSubOverflowTest(masm, &exit, 0xD0, -2); 1181 SmiSubOverflowTest(masm, &exit, 0xE0, -42000); 1182 SmiSubOverflowTest(masm, &exit, 0xF0, Smi::kMinValue); 1183 SmiSubOverflowTest(masm, &exit, 0x100, 0); 1184 1185 __ xor_(rax, rax); // Success. 1186 __ bind(&exit); 1187 ExitCode(masm); 1188 __ ret(0); 1189 1190 CodeDesc desc; 1191 masm->GetCode(&desc); 1192 // Call the function from C++. 1193 int result = FUNCTION_CAST<F0>(buffer)(); 1194 CHECK_EQ(0, result); 1195} 1196 1197 1198 1199void TestSmiMul(MacroAssembler* masm, Label* exit, int id, int x, int y) { 1200 int64_t result = static_cast<int64_t>(x) * static_cast<int64_t>(y); 1201 bool negative_zero = (result == 0) && (x < 0 || y < 0); 1202 __ Move(rcx, Smi::FromInt(x)); 1203 __ movq(r11, rcx); 1204 __ Move(rdx, Smi::FromInt(y)); 1205 if (Smi::IsValid(result) && !negative_zero) { 1206 __ movl(rax, Immediate(id)); 1207 __ Move(r8, Smi::FromIntptr(result)); 1208 __ SmiMul(r9, rcx, rdx, exit); 1209 __ incq(rax); 1210 __ cmpq(r11, rcx); 1211 __ j(not_equal, exit); 1212 __ incq(rax); 1213 __ cmpq(r9, r8); 1214 __ j(not_equal, exit); 1215 1216 __ incq(rax); 1217 __ SmiMul(rcx, rcx, rdx, exit); 1218 __ cmpq(rcx, r8); 1219 __ j(not_equal, exit); 1220 } else { 1221 __ movl(rax, Immediate(id + 8)); 1222 Label overflow_ok, overflow_ok2; 1223 __ SmiMul(r9, rcx, rdx, &overflow_ok); 1224 __ jmp(exit); 1225 __ bind(&overflow_ok); 1226 __ incq(rax); 1227 __ cmpq(r11, rcx); 1228 __ j(not_equal, exit); 1229 __ incq(rax); 1230 __ SmiMul(rcx, rcx, rdx, &overflow_ok2); 1231 __ jmp(exit); 1232 __ bind(&overflow_ok2); 1233 // 31-bit version doesn't preserve rcx on failure. 1234 // __ incq(rax); 1235 // __ cmpq(r11, rcx); 1236 // __ j(not_equal, exit); 1237 } 1238} 1239 1240 1241TEST(SmiMul) { 1242 i::V8::Initialize(NULL); 1243 // Allocate an executable page of memory. 1244 size_t actual_size; 1245 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 1246 &actual_size, 1247 true)); 1248 CHECK(buffer); 1249 Isolate* isolate = CcTest::i_isolate(); 1250 HandleScope handles(isolate); 1251 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1252 1253 MacroAssembler* masm = &assembler; 1254 EntryCode(masm); 1255 Label exit; 1256 1257 TestSmiMul(masm, &exit, 0x10, 0, 0); 1258 TestSmiMul(masm, &exit, 0x20, -1, 0); 1259 TestSmiMul(masm, &exit, 0x30, 0, -1); 1260 TestSmiMul(masm, &exit, 0x40, -1, -1); 1261 TestSmiMul(masm, &exit, 0x50, 0x10000, 0x10000); 1262 TestSmiMul(masm, &exit, 0x60, 0x10000, 0xffff); 1263 TestSmiMul(masm, &exit, 0x70, 0x10000, 0xffff); 1264 TestSmiMul(masm, &exit, 0x80, Smi::kMaxValue, -1); 1265 TestSmiMul(masm, &exit, 0x90, Smi::kMaxValue, -2); 1266 TestSmiMul(masm, &exit, 0xa0, Smi::kMaxValue, 2); 1267 TestSmiMul(masm, &exit, 0xb0, (Smi::kMaxValue / 2), 2); 1268 TestSmiMul(masm, &exit, 0xc0, (Smi::kMaxValue / 2) + 1, 2); 1269 TestSmiMul(masm, &exit, 0xd0, (Smi::kMinValue / 2), 2); 1270 TestSmiMul(masm, &exit, 0xe0, (Smi::kMinValue / 2) - 1, 2); 1271 1272 __ xor_(rax, rax); // Success. 1273 __ bind(&exit); 1274 ExitCode(masm); 1275 __ ret(0); 1276 1277 CodeDesc desc; 1278 masm->GetCode(&desc); 1279 // Call the function from C++. 1280 int result = FUNCTION_CAST<F0>(buffer)(); 1281 CHECK_EQ(0, result); 1282} 1283 1284 1285void TestSmiDiv(MacroAssembler* masm, Label* exit, int id, int x, int y) { 1286 bool division_by_zero = (y == 0); 1287 bool negative_zero = (x == 0 && y < 0); 1288#if V8_TARGET_ARCH_X64 1289 bool overflow = (x == Smi::kMinValue && y < 0); // Safe approx. used. 1290#else 1291 bool overflow = (x == Smi::kMinValue && y == -1); 1292#endif 1293 bool fraction = !division_by_zero && !overflow && (x % y != 0); 1294 __ Move(r11, Smi::FromInt(x)); 1295 __ Move(r14, Smi::FromInt(y)); 1296 if (!fraction && !overflow && !negative_zero && !division_by_zero) { 1297 // Division succeeds 1298 __ movq(rcx, r11); 1299 __ movq(r15, Immediate(id)); 1300 int result = x / y; 1301 __ Move(r8, Smi::FromInt(result)); 1302 __ SmiDiv(r9, rcx, r14, exit); 1303 // Might have destroyed rcx and r14. 1304 __ incq(r15); 1305 __ cmpq(r9, r8); 1306 __ j(not_equal, exit); 1307 1308 __ incq(r15); 1309 __ movq(rcx, r11); 1310 __ Move(r14, Smi::FromInt(y)); 1311 __ cmpq(rcx, r11); 1312 __ j(not_equal, exit); 1313 1314 __ incq(r15); 1315 __ SmiDiv(rcx, rcx, r14, exit); 1316 1317 __ incq(r15); 1318 __ cmpq(rcx, r8); 1319 __ j(not_equal, exit); 1320 } else { 1321 // Division fails. 1322 __ movq(r15, Immediate(id + 8)); 1323 1324 Label fail_ok, fail_ok2; 1325 __ movq(rcx, r11); 1326 __ SmiDiv(r9, rcx, r14, &fail_ok); 1327 __ jmp(exit); 1328 __ bind(&fail_ok); 1329 1330 __ incq(r15); 1331 __ cmpq(rcx, r11); 1332 __ j(not_equal, exit); 1333 1334 __ incq(r15); 1335 __ SmiDiv(rcx, rcx, r14, &fail_ok2); 1336 __ jmp(exit); 1337 __ bind(&fail_ok2); 1338 1339 __ incq(r15); 1340 __ cmpq(rcx, r11); 1341 __ j(not_equal, exit); 1342 } 1343} 1344 1345 1346TEST(SmiDiv) { 1347 i::V8::Initialize(NULL); 1348 // Allocate an executable page of memory. 1349 size_t actual_size; 1350 byte* buffer = 1351 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, 1352 &actual_size, 1353 true)); 1354 CHECK(buffer); 1355 Isolate* isolate = CcTest::i_isolate(); 1356 HandleScope handles(isolate); 1357 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1358 1359 MacroAssembler* masm = &assembler; 1360 EntryCode(masm); 1361 Label exit; 1362 1363 __ push(r14); 1364 __ push(r15); 1365 TestSmiDiv(masm, &exit, 0x10, 1, 1); 1366 TestSmiDiv(masm, &exit, 0x20, 1, 0); 1367 TestSmiDiv(masm, &exit, 0x30, -1, 0); 1368 TestSmiDiv(masm, &exit, 0x40, 0, 1); 1369 TestSmiDiv(masm, &exit, 0x50, 0, -1); 1370 TestSmiDiv(masm, &exit, 0x60, 4, 2); 1371 TestSmiDiv(masm, &exit, 0x70, -4, 2); 1372 TestSmiDiv(masm, &exit, 0x80, 4, -2); 1373 TestSmiDiv(masm, &exit, 0x90, -4, -2); 1374 TestSmiDiv(masm, &exit, 0xa0, 3, 2); 1375 TestSmiDiv(masm, &exit, 0xb0, 3, 4); 1376 TestSmiDiv(masm, &exit, 0xc0, 1, Smi::kMaxValue); 1377 TestSmiDiv(masm, &exit, 0xd0, -1, Smi::kMaxValue); 1378 TestSmiDiv(masm, &exit, 0xe0, Smi::kMaxValue, 1); 1379 TestSmiDiv(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue); 1380 TestSmiDiv(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue); 1381 TestSmiDiv(masm, &exit, 0x110, Smi::kMaxValue, -1); 1382 TestSmiDiv(masm, &exit, 0x120, Smi::kMinValue, 1); 1383 TestSmiDiv(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue); 1384 TestSmiDiv(masm, &exit, 0x140, Smi::kMinValue, -1); 1385 1386 __ xor_(r15, r15); // Success. 1387 __ bind(&exit); 1388 __ movq(rax, r15); 1389 __ pop(r15); 1390 __ pop(r14); 1391 ExitCode(masm); 1392 __ ret(0); 1393 1394 CodeDesc desc; 1395 masm->GetCode(&desc); 1396 // Call the function from C++. 1397 int result = FUNCTION_CAST<F0>(buffer)(); 1398 CHECK_EQ(0, result); 1399} 1400 1401 1402void TestSmiMod(MacroAssembler* masm, Label* exit, int id, int x, int y) { 1403 bool division_by_zero = (y == 0); 1404 bool division_overflow = (x == Smi::kMinValue) && (y == -1); 1405 bool fraction = !division_by_zero && !division_overflow && ((x % y) != 0); 1406 bool negative_zero = (!fraction && x < 0); 1407 __ Move(rcx, Smi::FromInt(x)); 1408 __ movq(r11, rcx); 1409 __ Move(r14, Smi::FromInt(y)); 1410 if (!division_overflow && !negative_zero && !division_by_zero) { 1411 // Modulo succeeds 1412 __ movq(r15, Immediate(id)); 1413 int result = x % y; 1414 __ Move(r8, Smi::FromInt(result)); 1415 __ SmiMod(r9, rcx, r14, exit); 1416 1417 __ incq(r15); 1418 __ cmpq(r9, r8); 1419 __ j(not_equal, exit); 1420 1421 __ incq(r15); 1422 __ cmpq(rcx, r11); 1423 __ j(not_equal, exit); 1424 1425 __ incq(r15); 1426 __ SmiMod(rcx, rcx, r14, exit); 1427 1428 __ incq(r15); 1429 __ cmpq(rcx, r8); 1430 __ j(not_equal, exit); 1431 } else { 1432 // Modulo fails. 1433 __ movq(r15, Immediate(id + 8)); 1434 1435 Label fail_ok, fail_ok2; 1436 __ SmiMod(r9, rcx, r14, &fail_ok); 1437 __ jmp(exit); 1438 __ bind(&fail_ok); 1439 1440 __ incq(r15); 1441 __ cmpq(rcx, r11); 1442 __ j(not_equal, exit); 1443 1444 __ incq(r15); 1445 __ SmiMod(rcx, rcx, r14, &fail_ok2); 1446 __ jmp(exit); 1447 __ bind(&fail_ok2); 1448 1449 __ incq(r15); 1450 __ cmpq(rcx, r11); 1451 __ j(not_equal, exit); 1452 } 1453} 1454 1455 1456TEST(SmiMod) { 1457 i::V8::Initialize(NULL); 1458 // Allocate an executable page of memory. 1459 size_t actual_size; 1460 byte* buffer = 1461 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, 1462 &actual_size, 1463 true)); 1464 CHECK(buffer); 1465 Isolate* isolate = CcTest::i_isolate(); 1466 HandleScope handles(isolate); 1467 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1468 1469 MacroAssembler* masm = &assembler; 1470 EntryCode(masm); 1471 Label exit; 1472 1473 __ push(r14); 1474 __ push(r15); 1475 TestSmiMod(masm, &exit, 0x10, 1, 1); 1476 TestSmiMod(masm, &exit, 0x20, 1, 0); 1477 TestSmiMod(masm, &exit, 0x30, -1, 0); 1478 TestSmiMod(masm, &exit, 0x40, 0, 1); 1479 TestSmiMod(masm, &exit, 0x50, 0, -1); 1480 TestSmiMod(masm, &exit, 0x60, 4, 2); 1481 TestSmiMod(masm, &exit, 0x70, -4, 2); 1482 TestSmiMod(masm, &exit, 0x80, 4, -2); 1483 TestSmiMod(masm, &exit, 0x90, -4, -2); 1484 TestSmiMod(masm, &exit, 0xa0, 3, 2); 1485 TestSmiMod(masm, &exit, 0xb0, 3, 4); 1486 TestSmiMod(masm, &exit, 0xc0, 1, Smi::kMaxValue); 1487 TestSmiMod(masm, &exit, 0xd0, -1, Smi::kMaxValue); 1488 TestSmiMod(masm, &exit, 0xe0, Smi::kMaxValue, 1); 1489 TestSmiMod(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue); 1490 TestSmiMod(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue); 1491 TestSmiMod(masm, &exit, 0x110, Smi::kMaxValue, -1); 1492 TestSmiMod(masm, &exit, 0x120, Smi::kMinValue, 1); 1493 TestSmiMod(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue); 1494 TestSmiMod(masm, &exit, 0x140, Smi::kMinValue, -1); 1495 1496 __ xor_(r15, r15); // Success. 1497 __ bind(&exit); 1498 __ movq(rax, r15); 1499 __ pop(r15); 1500 __ pop(r14); 1501 ExitCode(masm); 1502 __ ret(0); 1503 1504 CodeDesc desc; 1505 masm->GetCode(&desc); 1506 // Call the function from C++. 1507 int result = FUNCTION_CAST<F0>(buffer)(); 1508 CHECK_EQ(0, result); 1509} 1510 1511 1512void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) { 1513 __ movl(rax, Immediate(id)); 1514 1515 for (int i = 0; i < 8; i++) { 1516 __ Move(rcx, Smi::FromInt(x)); 1517 SmiIndex index = masm->SmiToIndex(rdx, rcx, i); 1518 ASSERT(index.reg.is(rcx) || index.reg.is(rdx)); 1519 __ shl(index.reg, Immediate(index.scale)); 1520 __ Set(r8, static_cast<intptr_t>(x) << i); 1521 __ cmpq(index.reg, r8); 1522 __ j(not_equal, exit); 1523 __ incq(rax); 1524 __ Move(rcx, Smi::FromInt(x)); 1525 index = masm->SmiToIndex(rcx, rcx, i); 1526 ASSERT(index.reg.is(rcx)); 1527 __ shl(rcx, Immediate(index.scale)); 1528 __ Set(r8, static_cast<intptr_t>(x) << i); 1529 __ cmpq(rcx, r8); 1530 __ j(not_equal, exit); 1531 __ incq(rax); 1532 1533 __ Move(rcx, Smi::FromInt(x)); 1534 index = masm->SmiToNegativeIndex(rdx, rcx, i); 1535 ASSERT(index.reg.is(rcx) || index.reg.is(rdx)); 1536 __ shl(index.reg, Immediate(index.scale)); 1537 __ Set(r8, static_cast<intptr_t>(-x) << i); 1538 __ cmpq(index.reg, r8); 1539 __ j(not_equal, exit); 1540 __ incq(rax); 1541 __ Move(rcx, Smi::FromInt(x)); 1542 index = masm->SmiToNegativeIndex(rcx, rcx, i); 1543 ASSERT(index.reg.is(rcx)); 1544 __ shl(rcx, Immediate(index.scale)); 1545 __ Set(r8, static_cast<intptr_t>(-x) << i); 1546 __ cmpq(rcx, r8); 1547 __ j(not_equal, exit); 1548 __ incq(rax); 1549 } 1550} 1551 1552 1553TEST(SmiIndex) { 1554 i::V8::Initialize(NULL); 1555 // Allocate an executable page of memory. 1556 size_t actual_size; 1557 byte* buffer = 1558 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4, 1559 &actual_size, 1560 true)); 1561 CHECK(buffer); 1562 Isolate* isolate = CcTest::i_isolate(); 1563 HandleScope handles(isolate); 1564 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1565 1566 MacroAssembler* masm = &assembler; 1567 EntryCode(masm); 1568 Label exit; 1569 1570 TestSmiIndex(masm, &exit, 0x10, 0); 1571 TestSmiIndex(masm, &exit, 0x20, 1); 1572 TestSmiIndex(masm, &exit, 0x30, 100); 1573 TestSmiIndex(masm, &exit, 0x40, 1000); 1574 TestSmiIndex(masm, &exit, 0x50, Smi::kMaxValue); 1575 1576 __ xor_(rax, rax); // Success. 1577 __ bind(&exit); 1578 ExitCode(masm); 1579 __ ret(0); 1580 1581 CodeDesc desc; 1582 masm->GetCode(&desc); 1583 // Call the function from C++. 1584 int result = FUNCTION_CAST<F0>(buffer)(); 1585 CHECK_EQ(0, result); 1586} 1587 1588 1589void TestSelectNonSmi(MacroAssembler* masm, Label* exit, int id, int x, int y) { 1590 __ movl(rax, Immediate(id)); 1591 __ Move(rcx, Smi::FromInt(x)); 1592 __ Move(rdx, Smi::FromInt(y)); 1593 __ xor_(rdx, Immediate(kSmiTagMask)); 1594 __ SelectNonSmi(r9, rcx, rdx, exit); 1595 1596 __ incq(rax); 1597 __ cmpq(r9, rdx); 1598 __ j(not_equal, exit); 1599 1600 __ incq(rax); 1601 __ Move(rcx, Smi::FromInt(x)); 1602 __ Move(rdx, Smi::FromInt(y)); 1603 __ xor_(rcx, Immediate(kSmiTagMask)); 1604 __ SelectNonSmi(r9, rcx, rdx, exit); 1605 1606 __ incq(rax); 1607 __ cmpq(r9, rcx); 1608 __ j(not_equal, exit); 1609 1610 __ incq(rax); 1611 Label fail_ok; 1612 __ Move(rcx, Smi::FromInt(x)); 1613 __ Move(rdx, Smi::FromInt(y)); 1614 __ xor_(rcx, Immediate(kSmiTagMask)); 1615 __ xor_(rdx, Immediate(kSmiTagMask)); 1616 __ SelectNonSmi(r9, rcx, rdx, &fail_ok); 1617 __ jmp(exit); 1618 __ bind(&fail_ok); 1619} 1620 1621 1622TEST(SmiSelectNonSmi) { 1623 i::V8::Initialize(NULL); 1624 // Allocate an executable page of memory. 1625 size_t actual_size; 1626 byte* buffer = 1627 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, 1628 &actual_size, 1629 true)); 1630 CHECK(buffer); 1631 Isolate* isolate = CcTest::i_isolate(); 1632 HandleScope handles(isolate); 1633 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1634 1635 MacroAssembler* masm = &assembler; 1636 EntryCode(masm); 1637 Label exit; 1638 1639 TestSelectNonSmi(masm, &exit, 0x10, 0, 0); 1640 TestSelectNonSmi(masm, &exit, 0x20, 0, 1); 1641 TestSelectNonSmi(masm, &exit, 0x30, 1, 0); 1642 TestSelectNonSmi(masm, &exit, 0x40, 0, -1); 1643 TestSelectNonSmi(masm, &exit, 0x50, -1, 0); 1644 TestSelectNonSmi(masm, &exit, 0x60, -1, -1); 1645 TestSelectNonSmi(masm, &exit, 0x70, 1, 1); 1646 TestSelectNonSmi(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue); 1647 TestSelectNonSmi(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue); 1648 1649 __ xor_(rax, rax); // Success. 1650 __ bind(&exit); 1651 ExitCode(masm); 1652 __ ret(0); 1653 1654 CodeDesc desc; 1655 masm->GetCode(&desc); 1656 // Call the function from C++. 1657 int result = FUNCTION_CAST<F0>(buffer)(); 1658 CHECK_EQ(0, result); 1659} 1660 1661 1662void TestSmiAnd(MacroAssembler* masm, Label* exit, int id, int x, int y) { 1663 int result = x & y; 1664 1665 __ movl(rax, Immediate(id)); 1666 1667 __ Move(rcx, Smi::FromInt(x)); 1668 __ movq(r11, rcx); 1669 __ Move(rdx, Smi::FromInt(y)); 1670 __ Move(r8, Smi::FromInt(result)); 1671 __ SmiAnd(r9, rcx, rdx); 1672 __ cmpq(r8, r9); 1673 __ j(not_equal, exit); 1674 1675 __ incq(rax); 1676 __ cmpq(r11, rcx); 1677 __ j(not_equal, exit); 1678 1679 __ incq(rax); 1680 __ SmiAnd(rcx, rcx, rdx); 1681 __ cmpq(r8, rcx); 1682 __ j(not_equal, exit); 1683 1684 __ movq(rcx, r11); 1685 __ incq(rax); 1686 __ SmiAndConstant(r9, rcx, Smi::FromInt(y)); 1687 __ cmpq(r8, r9); 1688 __ j(not_equal, exit); 1689 1690 __ incq(rax); 1691 __ cmpq(r11, rcx); 1692 __ j(not_equal, exit); 1693 1694 __ incq(rax); 1695 __ SmiAndConstant(rcx, rcx, Smi::FromInt(y)); 1696 __ cmpq(r8, rcx); 1697 __ j(not_equal, exit); 1698} 1699 1700 1701TEST(SmiAnd) { 1702 i::V8::Initialize(NULL); 1703 // Allocate an executable page of memory. 1704 size_t actual_size; 1705 byte* buffer = 1706 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, 1707 &actual_size, 1708 true)); 1709 CHECK(buffer); 1710 Isolate* isolate = CcTest::i_isolate(); 1711 HandleScope handles(isolate); 1712 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1713 1714 MacroAssembler* masm = &assembler; 1715 EntryCode(masm); 1716 Label exit; 1717 1718 TestSmiAnd(masm, &exit, 0x10, 0, 0); 1719 TestSmiAnd(masm, &exit, 0x20, 0, 1); 1720 TestSmiAnd(masm, &exit, 0x30, 1, 0); 1721 TestSmiAnd(masm, &exit, 0x40, 0, -1); 1722 TestSmiAnd(masm, &exit, 0x50, -1, 0); 1723 TestSmiAnd(masm, &exit, 0x60, -1, -1); 1724 TestSmiAnd(masm, &exit, 0x70, 1, 1); 1725 TestSmiAnd(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue); 1726 TestSmiAnd(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue); 1727 TestSmiAnd(masm, &exit, 0xA0, Smi::kMinValue, -1); 1728 TestSmiAnd(masm, &exit, 0xB0, Smi::kMinValue, -1); 1729 1730 __ xor_(rax, rax); // Success. 1731 __ bind(&exit); 1732 ExitCode(masm); 1733 __ ret(0); 1734 1735 CodeDesc desc; 1736 masm->GetCode(&desc); 1737 // Call the function from C++. 1738 int result = FUNCTION_CAST<F0>(buffer)(); 1739 CHECK_EQ(0, result); 1740} 1741 1742 1743void TestSmiOr(MacroAssembler* masm, Label* exit, int id, int x, int y) { 1744 int result = x | y; 1745 1746 __ movl(rax, Immediate(id)); 1747 1748 __ Move(rcx, Smi::FromInt(x)); 1749 __ movq(r11, rcx); 1750 __ Move(rdx, Smi::FromInt(y)); 1751 __ Move(r8, Smi::FromInt(result)); 1752 __ SmiOr(r9, rcx, rdx); 1753 __ cmpq(r8, r9); 1754 __ j(not_equal, exit); 1755 1756 __ incq(rax); 1757 __ cmpq(r11, rcx); 1758 __ j(not_equal, exit); 1759 1760 __ incq(rax); 1761 __ SmiOr(rcx, rcx, rdx); 1762 __ cmpq(r8, rcx); 1763 __ j(not_equal, exit); 1764 1765 __ movq(rcx, r11); 1766 __ incq(rax); 1767 __ SmiOrConstant(r9, rcx, Smi::FromInt(y)); 1768 __ cmpq(r8, r9); 1769 __ j(not_equal, exit); 1770 1771 __ incq(rax); 1772 __ cmpq(r11, rcx); 1773 __ j(not_equal, exit); 1774 1775 __ incq(rax); 1776 __ SmiOrConstant(rcx, rcx, Smi::FromInt(y)); 1777 __ cmpq(r8, rcx); 1778 __ j(not_equal, exit); 1779} 1780 1781 1782TEST(SmiOr) { 1783 i::V8::Initialize(NULL); 1784 // Allocate an executable page of memory. 1785 size_t actual_size; 1786 byte* buffer = 1787 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, 1788 &actual_size, 1789 true)); 1790 CHECK(buffer); 1791 Isolate* isolate = CcTest::i_isolate(); 1792 HandleScope handles(isolate); 1793 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1794 1795 MacroAssembler* masm = &assembler; 1796 EntryCode(masm); 1797 Label exit; 1798 1799 TestSmiOr(masm, &exit, 0x10, 0, 0); 1800 TestSmiOr(masm, &exit, 0x20, 0, 1); 1801 TestSmiOr(masm, &exit, 0x30, 1, 0); 1802 TestSmiOr(masm, &exit, 0x40, 0, -1); 1803 TestSmiOr(masm, &exit, 0x50, -1, 0); 1804 TestSmiOr(masm, &exit, 0x60, -1, -1); 1805 TestSmiOr(masm, &exit, 0x70, 1, 1); 1806 TestSmiOr(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue); 1807 TestSmiOr(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue); 1808 TestSmiOr(masm, &exit, 0xA0, Smi::kMinValue, -1); 1809 TestSmiOr(masm, &exit, 0xB0, 0x05555555, 0x01234567); 1810 TestSmiOr(masm, &exit, 0xC0, 0x05555555, 0x0fedcba9); 1811 TestSmiOr(masm, &exit, 0xD0, Smi::kMinValue, -1); 1812 1813 __ xor_(rax, rax); // Success. 1814 __ bind(&exit); 1815 ExitCode(masm); 1816 __ ret(0); 1817 1818 CodeDesc desc; 1819 masm->GetCode(&desc); 1820 // Call the function from C++. 1821 int result = FUNCTION_CAST<F0>(buffer)(); 1822 CHECK_EQ(0, result); 1823} 1824 1825 1826void TestSmiXor(MacroAssembler* masm, Label* exit, int id, int x, int y) { 1827 int result = x ^ y; 1828 1829 __ movl(rax, Immediate(id)); 1830 1831 __ Move(rcx, Smi::FromInt(x)); 1832 __ movq(r11, rcx); 1833 __ Move(rdx, Smi::FromInt(y)); 1834 __ Move(r8, Smi::FromInt(result)); 1835 __ SmiXor(r9, rcx, rdx); 1836 __ cmpq(r8, r9); 1837 __ j(not_equal, exit); 1838 1839 __ incq(rax); 1840 __ cmpq(r11, rcx); 1841 __ j(not_equal, exit); 1842 1843 __ incq(rax); 1844 __ SmiXor(rcx, rcx, rdx); 1845 __ cmpq(r8, rcx); 1846 __ j(not_equal, exit); 1847 1848 __ movq(rcx, r11); 1849 __ incq(rax); 1850 __ SmiXorConstant(r9, rcx, Smi::FromInt(y)); 1851 __ cmpq(r8, r9); 1852 __ j(not_equal, exit); 1853 1854 __ incq(rax); 1855 __ cmpq(r11, rcx); 1856 __ j(not_equal, exit); 1857 1858 __ incq(rax); 1859 __ SmiXorConstant(rcx, rcx, Smi::FromInt(y)); 1860 __ cmpq(r8, rcx); 1861 __ j(not_equal, exit); 1862} 1863 1864 1865TEST(SmiXor) { 1866 i::V8::Initialize(NULL); 1867 // Allocate an executable page of memory. 1868 size_t actual_size; 1869 byte* buffer = 1870 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, 1871 &actual_size, 1872 true)); 1873 CHECK(buffer); 1874 Isolate* isolate = CcTest::i_isolate(); 1875 HandleScope handles(isolate); 1876 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1877 1878 MacroAssembler* masm = &assembler; 1879 EntryCode(masm); 1880 Label exit; 1881 1882 TestSmiXor(masm, &exit, 0x10, 0, 0); 1883 TestSmiXor(masm, &exit, 0x20, 0, 1); 1884 TestSmiXor(masm, &exit, 0x30, 1, 0); 1885 TestSmiXor(masm, &exit, 0x40, 0, -1); 1886 TestSmiXor(masm, &exit, 0x50, -1, 0); 1887 TestSmiXor(masm, &exit, 0x60, -1, -1); 1888 TestSmiXor(masm, &exit, 0x70, 1, 1); 1889 TestSmiXor(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue); 1890 TestSmiXor(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue); 1891 TestSmiXor(masm, &exit, 0xA0, Smi::kMinValue, -1); 1892 TestSmiXor(masm, &exit, 0xB0, 0x5555555, 0x01234567); 1893 TestSmiXor(masm, &exit, 0xC0, 0x5555555, 0x0fedcba9); 1894 TestSmiXor(masm, &exit, 0xD0, Smi::kMinValue, -1); 1895 1896 __ xor_(rax, rax); // Success. 1897 __ bind(&exit); 1898 ExitCode(masm); 1899 __ ret(0); 1900 1901 CodeDesc desc; 1902 masm->GetCode(&desc); 1903 // Call the function from C++. 1904 int result = FUNCTION_CAST<F0>(buffer)(); 1905 CHECK_EQ(0, result); 1906} 1907 1908 1909void TestSmiNot(MacroAssembler* masm, Label* exit, int id, int x) { 1910 int result = ~x; 1911 __ movl(rax, Immediate(id)); 1912 1913 __ Move(r8, Smi::FromInt(result)); 1914 __ Move(rcx, Smi::FromInt(x)); 1915 __ movq(r11, rcx); 1916 1917 __ SmiNot(r9, rcx); 1918 __ cmpq(r9, r8); 1919 __ j(not_equal, exit); 1920 1921 __ incq(rax); 1922 __ cmpq(r11, rcx); 1923 __ j(not_equal, exit); 1924 1925 __ incq(rax); 1926 __ SmiNot(rcx, rcx); 1927 __ cmpq(rcx, r8); 1928 __ j(not_equal, exit); 1929} 1930 1931 1932TEST(SmiNot) { 1933 i::V8::Initialize(NULL); 1934 // Allocate an executable page of memory. 1935 size_t actual_size; 1936 byte* buffer = 1937 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 1938 &actual_size, 1939 true)); 1940 CHECK(buffer); 1941 Isolate* isolate = CcTest::i_isolate(); 1942 HandleScope handles(isolate); 1943 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 1944 1945 MacroAssembler* masm = &assembler; 1946 EntryCode(masm); 1947 Label exit; 1948 1949 TestSmiNot(masm, &exit, 0x10, 0); 1950 TestSmiNot(masm, &exit, 0x20, 1); 1951 TestSmiNot(masm, &exit, 0x30, -1); 1952 TestSmiNot(masm, &exit, 0x40, 127); 1953 TestSmiNot(masm, &exit, 0x50, 65535); 1954 TestSmiNot(masm, &exit, 0x60, Smi::kMinValue); 1955 TestSmiNot(masm, &exit, 0x70, Smi::kMaxValue); 1956 TestSmiNot(masm, &exit, 0x80, 0x05555555); 1957 1958 __ xor_(rax, rax); // Success. 1959 __ bind(&exit); 1960 ExitCode(masm); 1961 __ ret(0); 1962 1963 CodeDesc desc; 1964 masm->GetCode(&desc); 1965 // Call the function from C++. 1966 int result = FUNCTION_CAST<F0>(buffer)(); 1967 CHECK_EQ(0, result); 1968} 1969 1970 1971void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) { 1972 const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1}; 1973 const int kNumShifts = 5; 1974 __ movl(rax, Immediate(id)); 1975 for (int i = 0; i < kNumShifts; i++) { 1976 // rax == id + i * 10. 1977 int shift = shifts[i]; 1978 int result = x << shift; 1979 CHECK(Smi::IsValid(result)); 1980 __ Move(r8, Smi::FromInt(result)); 1981 __ Move(rcx, Smi::FromInt(x)); 1982 __ SmiShiftLeftConstant(r9, rcx, shift); 1983 1984 __ incq(rax); 1985 __ cmpq(r9, r8); 1986 __ j(not_equal, exit); 1987 1988 __ incq(rax); 1989 __ Move(rcx, Smi::FromInt(x)); 1990 __ SmiShiftLeftConstant(rcx, rcx, shift); 1991 1992 __ incq(rax); 1993 __ cmpq(rcx, r8); 1994 __ j(not_equal, exit); 1995 1996 __ incq(rax); 1997 __ Move(rdx, Smi::FromInt(x)); 1998 __ Move(rcx, Smi::FromInt(shift)); 1999 __ SmiShiftLeft(r9, rdx, rcx); 2000 2001 __ incq(rax); 2002 __ cmpq(r9, r8); 2003 __ j(not_equal, exit); 2004 2005 __ incq(rax); 2006 __ Move(rdx, Smi::FromInt(x)); 2007 __ Move(r11, Smi::FromInt(shift)); 2008 __ SmiShiftLeft(r9, rdx, r11); 2009 2010 __ incq(rax); 2011 __ cmpq(r9, r8); 2012 __ j(not_equal, exit); 2013 2014 __ incq(rax); 2015 __ Move(rdx, Smi::FromInt(x)); 2016 __ Move(r11, Smi::FromInt(shift)); 2017 __ SmiShiftLeft(rdx, rdx, r11); 2018 2019 __ incq(rax); 2020 __ cmpq(rdx, r8); 2021 __ j(not_equal, exit); 2022 2023 __ incq(rax); 2024 } 2025} 2026 2027 2028TEST(SmiShiftLeft) { 2029 i::V8::Initialize(NULL); 2030 // Allocate an executable page of memory. 2031 size_t actual_size; 2032 byte* buffer = 2033 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 7, 2034 &actual_size, 2035 true)); 2036 CHECK(buffer); 2037 Isolate* isolate = CcTest::i_isolate(); 2038 HandleScope handles(isolate); 2039 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 2040 2041 MacroAssembler* masm = &assembler; 2042 EntryCode(masm); 2043 Label exit; 2044 2045 TestSmiShiftLeft(masm, &exit, 0x10, 0); 2046 TestSmiShiftLeft(masm, &exit, 0x50, 1); 2047 TestSmiShiftLeft(masm, &exit, 0x90, 127); 2048 TestSmiShiftLeft(masm, &exit, 0xD0, 65535); 2049 TestSmiShiftLeft(masm, &exit, 0x110, Smi::kMaxValue); 2050 TestSmiShiftLeft(masm, &exit, 0x150, Smi::kMinValue); 2051 TestSmiShiftLeft(masm, &exit, 0x190, -1); 2052 2053 __ xor_(rax, rax); // Success. 2054 __ bind(&exit); 2055 ExitCode(masm); 2056 __ ret(0); 2057 2058 CodeDesc desc; 2059 masm->GetCode(&desc); 2060 // Call the function from C++. 2061 int result = FUNCTION_CAST<F0>(buffer)(); 2062 CHECK_EQ(0, result); 2063} 2064 2065 2066void TestSmiShiftLogicalRight(MacroAssembler* masm, 2067 Label* exit, 2068 int id, 2069 int x) { 2070 const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1}; 2071 const int kNumShifts = 5; 2072 __ movl(rax, Immediate(id)); 2073 for (int i = 0; i < kNumShifts; i++) { 2074 int shift = shifts[i]; 2075 intptr_t result = static_cast<unsigned int>(x) >> shift; 2076 if (Smi::IsValid(result)) { 2077 __ Move(r8, Smi::FromInt(static_cast<int>(result))); 2078 __ Move(rcx, Smi::FromInt(x)); 2079 __ SmiShiftLogicalRightConstant(r9, rcx, shift, exit); 2080 2081 __ incq(rax); 2082 __ cmpq(r9, r8); 2083 __ j(not_equal, exit); 2084 2085 __ incq(rax); 2086 __ Move(rdx, Smi::FromInt(x)); 2087 __ Move(rcx, Smi::FromInt(shift)); 2088 __ SmiShiftLogicalRight(r9, rdx, rcx, exit); 2089 2090 __ incq(rax); 2091 __ cmpq(r9, r8); 2092 __ j(not_equal, exit); 2093 2094 __ incq(rax); 2095 __ Move(rdx, Smi::FromInt(x)); 2096 __ Move(r11, Smi::FromInt(shift)); 2097 __ SmiShiftLogicalRight(r9, rdx, r11, exit); 2098 2099 __ incq(rax); 2100 __ cmpq(r9, r8); 2101 __ j(not_equal, exit); 2102 2103 __ incq(rax); 2104 } else { 2105 // Cannot happen with long smis. 2106 Label fail_ok; 2107 __ Move(rcx, Smi::FromInt(x)); 2108 __ movq(r11, rcx); 2109 __ SmiShiftLogicalRightConstant(r9, rcx, shift, &fail_ok); 2110 __ jmp(exit); 2111 __ bind(&fail_ok); 2112 2113 __ incq(rax); 2114 __ cmpq(rcx, r11); 2115 __ j(not_equal, exit); 2116 2117 __ incq(rax); 2118 __ Move(r8, Smi::FromInt(shift)); 2119 Label fail_ok3; 2120 __ SmiShiftLogicalRight(r9, rcx, r8, &fail_ok3); 2121 __ jmp(exit); 2122 __ bind(&fail_ok3); 2123 2124 __ incq(rax); 2125 __ cmpq(rcx, r11); 2126 __ j(not_equal, exit); 2127 2128 __ addq(rax, Immediate(3)); 2129 } 2130 } 2131} 2132 2133 2134TEST(SmiShiftLogicalRight) { 2135 i::V8::Initialize(NULL); 2136 // Allocate an executable page of memory. 2137 size_t actual_size; 2138 byte* buffer = 2139 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 5, 2140 &actual_size, 2141 true)); 2142 CHECK(buffer); 2143 Isolate* isolate = CcTest::i_isolate(); 2144 HandleScope handles(isolate); 2145 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 2146 2147 MacroAssembler* masm = &assembler; 2148 EntryCode(masm); 2149 Label exit; 2150 2151 TestSmiShiftLogicalRight(masm, &exit, 0x10, 0); 2152 TestSmiShiftLogicalRight(masm, &exit, 0x30, 1); 2153 TestSmiShiftLogicalRight(masm, &exit, 0x50, 127); 2154 TestSmiShiftLogicalRight(masm, &exit, 0x70, 65535); 2155 TestSmiShiftLogicalRight(masm, &exit, 0x90, Smi::kMaxValue); 2156 TestSmiShiftLogicalRight(masm, &exit, 0xB0, Smi::kMinValue); 2157 TestSmiShiftLogicalRight(masm, &exit, 0xD0, -1); 2158 2159 __ xor_(rax, rax); // Success. 2160 __ bind(&exit); 2161 ExitCode(masm); 2162 __ ret(0); 2163 2164 CodeDesc desc; 2165 masm->GetCode(&desc); 2166 // Call the function from C++. 2167 int result = FUNCTION_CAST<F0>(buffer)(); 2168 CHECK_EQ(0, result); 2169} 2170 2171 2172void TestSmiShiftArithmeticRight(MacroAssembler* masm, 2173 Label* exit, 2174 int id, 2175 int x) { 2176 const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1}; 2177 const int kNumShifts = 5; 2178 __ movl(rax, Immediate(id)); 2179 for (int i = 0; i < kNumShifts; i++) { 2180 int shift = shifts[i]; 2181 // Guaranteed arithmetic shift. 2182 int result = (x < 0) ? ~((~x) >> shift) : (x >> shift); 2183 __ Move(r8, Smi::FromInt(result)); 2184 __ Move(rcx, Smi::FromInt(x)); 2185 __ SmiShiftArithmeticRightConstant(rcx, rcx, shift); 2186 2187 __ cmpq(rcx, r8); 2188 __ j(not_equal, exit); 2189 2190 __ incq(rax); 2191 __ Move(rdx, Smi::FromInt(x)); 2192 __ Move(r11, Smi::FromInt(shift)); 2193 __ SmiShiftArithmeticRight(rdx, rdx, r11); 2194 2195 __ cmpq(rdx, r8); 2196 __ j(not_equal, exit); 2197 2198 __ incq(rax); 2199 } 2200} 2201 2202 2203TEST(SmiShiftArithmeticRight) { 2204 i::V8::Initialize(NULL); 2205 // Allocate an executable page of memory. 2206 size_t actual_size; 2207 byte* buffer = 2208 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3, 2209 &actual_size, 2210 true)); 2211 CHECK(buffer); 2212 Isolate* isolate = CcTest::i_isolate(); 2213 HandleScope handles(isolate); 2214 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 2215 2216 MacroAssembler* masm = &assembler; 2217 EntryCode(masm); 2218 Label exit; 2219 2220 TestSmiShiftArithmeticRight(masm, &exit, 0x10, 0); 2221 TestSmiShiftArithmeticRight(masm, &exit, 0x20, 1); 2222 TestSmiShiftArithmeticRight(masm, &exit, 0x30, 127); 2223 TestSmiShiftArithmeticRight(masm, &exit, 0x40, 65535); 2224 TestSmiShiftArithmeticRight(masm, &exit, 0x50, Smi::kMaxValue); 2225 TestSmiShiftArithmeticRight(masm, &exit, 0x60, Smi::kMinValue); 2226 TestSmiShiftArithmeticRight(masm, &exit, 0x70, -1); 2227 2228 __ xor_(rax, rax); // Success. 2229 __ bind(&exit); 2230 ExitCode(masm); 2231 __ ret(0); 2232 2233 CodeDesc desc; 2234 masm->GetCode(&desc); 2235 // Call the function from C++. 2236 int result = FUNCTION_CAST<F0>(buffer)(); 2237 CHECK_EQ(0, result); 2238} 2239 2240 2241void TestPositiveSmiPowerUp(MacroAssembler* masm, Label* exit, int id, int x) { 2242 ASSERT(x >= 0); 2243 int powers[] = { 0, 1, 2, 3, 8, 16, 24, 31 }; 2244 int power_count = 8; 2245 __ movl(rax, Immediate(id)); 2246 for (int i = 0; i < power_count; i++) { 2247 int power = powers[i]; 2248 intptr_t result = static_cast<intptr_t>(x) << power; 2249 __ Set(r8, result); 2250 __ Move(rcx, Smi::FromInt(x)); 2251 __ movq(r11, rcx); 2252 __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rcx, power); 2253 __ cmpq(rdx, r8); 2254 __ j(not_equal, exit); 2255 __ incq(rax); 2256 __ cmpq(r11, rcx); // rcx unchanged. 2257 __ j(not_equal, exit); 2258 __ incq(rax); 2259 __ PositiveSmiTimesPowerOfTwoToInteger64(rcx, rcx, power); 2260 __ cmpq(rdx, r8); 2261 __ j(not_equal, exit); 2262 __ incq(rax); 2263 } 2264} 2265 2266 2267TEST(PositiveSmiTimesPowerOfTwoToInteger64) { 2268 i::V8::Initialize(NULL); 2269 // Allocate an executable page of memory. 2270 size_t actual_size; 2271 byte* buffer = 2272 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4, 2273 &actual_size, 2274 true)); 2275 CHECK(buffer); 2276 Isolate* isolate = CcTest::i_isolate(); 2277 HandleScope handles(isolate); 2278 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 2279 2280 MacroAssembler* masm = &assembler; 2281 EntryCode(masm); 2282 Label exit; 2283 2284 TestPositiveSmiPowerUp(masm, &exit, 0x20, 0); 2285 TestPositiveSmiPowerUp(masm, &exit, 0x40, 1); 2286 TestPositiveSmiPowerUp(masm, &exit, 0x60, 127); 2287 TestPositiveSmiPowerUp(masm, &exit, 0x80, 128); 2288 TestPositiveSmiPowerUp(masm, &exit, 0xA0, 255); 2289 TestPositiveSmiPowerUp(masm, &exit, 0xC0, 256); 2290 TestPositiveSmiPowerUp(masm, &exit, 0x100, 65535); 2291 TestPositiveSmiPowerUp(masm, &exit, 0x120, 65536); 2292 TestPositiveSmiPowerUp(masm, &exit, 0x140, Smi::kMaxValue); 2293 2294 __ xor_(rax, rax); // Success. 2295 __ bind(&exit); 2296 ExitCode(masm); 2297 __ ret(0); 2298 2299 CodeDesc desc; 2300 masm->GetCode(&desc); 2301 // Call the function from C++. 2302 int result = FUNCTION_CAST<F0>(buffer)(); 2303 CHECK_EQ(0, result); 2304} 2305 2306 2307TEST(OperandOffset) { 2308 i::V8::Initialize(NULL); 2309 uint32_t data[256]; 2310 for (uint32_t i = 0; i < 256; i++) { data[i] = i * 0x01010101; } 2311 2312 // Allocate an executable page of memory. 2313 size_t actual_size; 2314 byte* buffer = 2315 static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, 2316 &actual_size, 2317 true)); 2318 CHECK(buffer); 2319 Isolate* isolate = CcTest::i_isolate(); 2320 HandleScope handles(isolate); 2321 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 2322 2323 MacroAssembler* masm = &assembler; 2324 Label exit; 2325 2326 EntryCode(masm); 2327 __ push(r13); 2328 __ push(r14); 2329 __ push(rbx); 2330 __ push(rbp); 2331 __ push(Immediate(0x100)); // <-- rbp 2332 __ movq(rbp, rsp); 2333 __ push(Immediate(0x101)); 2334 __ push(Immediate(0x102)); 2335 __ push(Immediate(0x103)); 2336 __ push(Immediate(0x104)); 2337 __ push(Immediate(0x105)); // <-- rbx 2338 __ push(Immediate(0x106)); 2339 __ push(Immediate(0x107)); 2340 __ push(Immediate(0x108)); 2341 __ push(Immediate(0x109)); // <-- rsp 2342 // rbp = rsp[9] 2343 // r15 = rsp[3] 2344 // rbx = rsp[5] 2345 // r13 = rsp[7] 2346 __ lea(r14, Operand(rsp, 3 * kPointerSize)); 2347 __ lea(r13, Operand(rbp, -3 * kPointerSize)); 2348 __ lea(rbx, Operand(rbp, -5 * kPointerSize)); 2349 __ movl(rcx, Immediate(2)); 2350 __ movq(r8, reinterpret_cast<Address>(&data[128]), RelocInfo::NONE64); 2351 __ movl(rax, Immediate(1)); 2352 2353 Operand sp0 = Operand(rsp, 0); 2354 2355 // Test 1. 2356 __ movl(rdx, sp0); // Sanity check. 2357 __ cmpl(rdx, Immediate(0x109)); 2358 __ j(not_equal, &exit); 2359 __ incq(rax); 2360 2361 // Test 2. 2362 // Zero to non-zero displacement. 2363 __ movl(rdx, Operand(sp0, 2 * kPointerSize)); 2364 __ cmpl(rdx, Immediate(0x107)); 2365 __ j(not_equal, &exit); 2366 __ incq(rax); 2367 2368 Operand sp2 = Operand(rsp, 2 * kPointerSize); 2369 2370 // Test 3. 2371 __ movl(rdx, sp2); // Sanity check. 2372 __ cmpl(rdx, Immediate(0x107)); 2373 __ j(not_equal, &exit); 2374 __ incq(rax); 2375 2376 __ movl(rdx, Operand(sp2, 2 * kPointerSize)); 2377 __ cmpl(rdx, Immediate(0x105)); 2378 __ j(not_equal, &exit); 2379 __ incq(rax); 2380 2381 // Non-zero to zero displacement. 2382 __ movl(rdx, Operand(sp2, -2 * kPointerSize)); 2383 __ cmpl(rdx, Immediate(0x109)); 2384 __ j(not_equal, &exit); 2385 __ incq(rax); 2386 2387 Operand sp2c2 = Operand(rsp, rcx, times_pointer_size, 2 * kPointerSize); 2388 2389 // Test 6. 2390 __ movl(rdx, sp2c2); // Sanity check. 2391 __ cmpl(rdx, Immediate(0x105)); 2392 __ j(not_equal, &exit); 2393 __ incq(rax); 2394 2395 __ movl(rdx, Operand(sp2c2, 2 * kPointerSize)); 2396 __ cmpl(rdx, Immediate(0x103)); 2397 __ j(not_equal, &exit); 2398 __ incq(rax); 2399 2400 // Non-zero to zero displacement. 2401 __ movl(rdx, Operand(sp2c2, -2 * kPointerSize)); 2402 __ cmpl(rdx, Immediate(0x107)); 2403 __ j(not_equal, &exit); 2404 __ incq(rax); 2405 2406 2407 Operand bp0 = Operand(rbp, 0); 2408 2409 // Test 9. 2410 __ movl(rdx, bp0); // Sanity check. 2411 __ cmpl(rdx, Immediate(0x100)); 2412 __ j(not_equal, &exit); 2413 __ incq(rax); 2414 2415 // Zero to non-zero displacement. 2416 __ movl(rdx, Operand(bp0, -2 * kPointerSize)); 2417 __ cmpl(rdx, Immediate(0x102)); 2418 __ j(not_equal, &exit); 2419 __ incq(rax); 2420 2421 Operand bp2 = Operand(rbp, -2 * kPointerSize); 2422 2423 // Test 11. 2424 __ movl(rdx, bp2); // Sanity check. 2425 __ cmpl(rdx, Immediate(0x102)); 2426 __ j(not_equal, &exit); 2427 __ incq(rax); 2428 2429 // Non-zero to zero displacement. 2430 __ movl(rdx, Operand(bp2, 2 * kPointerSize)); 2431 __ cmpl(rdx, Immediate(0x100)); 2432 __ j(not_equal, &exit); 2433 __ incq(rax); 2434 2435 __ movl(rdx, Operand(bp2, -2 * kPointerSize)); 2436 __ cmpl(rdx, Immediate(0x104)); 2437 __ j(not_equal, &exit); 2438 __ incq(rax); 2439 2440 Operand bp2c4 = Operand(rbp, rcx, times_pointer_size, -4 * kPointerSize); 2441 2442 // Test 14: 2443 __ movl(rdx, bp2c4); // Sanity check. 2444 __ cmpl(rdx, Immediate(0x102)); 2445 __ j(not_equal, &exit); 2446 __ incq(rax); 2447 2448 __ movl(rdx, Operand(bp2c4, 2 * kPointerSize)); 2449 __ cmpl(rdx, Immediate(0x100)); 2450 __ j(not_equal, &exit); 2451 __ incq(rax); 2452 2453 __ movl(rdx, Operand(bp2c4, -2 * kPointerSize)); 2454 __ cmpl(rdx, Immediate(0x104)); 2455 __ j(not_equal, &exit); 2456 __ incq(rax); 2457 2458 Operand bx0 = Operand(rbx, 0); 2459 2460 // Test 17. 2461 __ movl(rdx, bx0); // Sanity check. 2462 __ cmpl(rdx, Immediate(0x105)); 2463 __ j(not_equal, &exit); 2464 __ incq(rax); 2465 2466 __ movl(rdx, Operand(bx0, 5 * kPointerSize)); 2467 __ cmpl(rdx, Immediate(0x100)); 2468 __ j(not_equal, &exit); 2469 __ incq(rax); 2470 2471 __ movl(rdx, Operand(bx0, -4 * kPointerSize)); 2472 __ cmpl(rdx, Immediate(0x109)); 2473 __ j(not_equal, &exit); 2474 __ incq(rax); 2475 2476 Operand bx2 = Operand(rbx, 2 * kPointerSize); 2477 2478 // Test 20. 2479 __ movl(rdx, bx2); // Sanity check. 2480 __ cmpl(rdx, Immediate(0x103)); 2481 __ j(not_equal, &exit); 2482 __ incq(rax); 2483 2484 __ movl(rdx, Operand(bx2, 2 * kPointerSize)); 2485 __ cmpl(rdx, Immediate(0x101)); 2486 __ j(not_equal, &exit); 2487 __ incq(rax); 2488 2489 // Non-zero to zero displacement. 2490 __ movl(rdx, Operand(bx2, -2 * kPointerSize)); 2491 __ cmpl(rdx, Immediate(0x105)); 2492 __ j(not_equal, &exit); 2493 __ incq(rax); 2494 2495 Operand bx2c2 = Operand(rbx, rcx, times_pointer_size, -2 * kPointerSize); 2496 2497 // Test 23. 2498 __ movl(rdx, bx2c2); // Sanity check. 2499 __ cmpl(rdx, Immediate(0x105)); 2500 __ j(not_equal, &exit); 2501 __ incq(rax); 2502 2503 __ movl(rdx, Operand(bx2c2, 2 * kPointerSize)); 2504 __ cmpl(rdx, Immediate(0x103)); 2505 __ j(not_equal, &exit); 2506 __ incq(rax); 2507 2508 __ movl(rdx, Operand(bx2c2, -2 * kPointerSize)); 2509 __ cmpl(rdx, Immediate(0x107)); 2510 __ j(not_equal, &exit); 2511 __ incq(rax); 2512 2513 Operand r80 = Operand(r8, 0); 2514 2515 // Test 26. 2516 __ movl(rdx, r80); // Sanity check. 2517 __ cmpl(rdx, Immediate(0x80808080)); 2518 __ j(not_equal, &exit); 2519 __ incq(rax); 2520 2521 __ movl(rdx, Operand(r80, -8 * kIntSize)); 2522 __ cmpl(rdx, Immediate(0x78787878)); 2523 __ j(not_equal, &exit); 2524 __ incq(rax); 2525 2526 __ movl(rdx, Operand(r80, 8 * kIntSize)); 2527 __ cmpl(rdx, Immediate(0x88888888)); 2528 __ j(not_equal, &exit); 2529 __ incq(rax); 2530 2531 __ movl(rdx, Operand(r80, -64 * kIntSize)); 2532 __ cmpl(rdx, Immediate(0x40404040)); 2533 __ j(not_equal, &exit); 2534 __ incq(rax); 2535 2536 __ movl(rdx, Operand(r80, 64 * kIntSize)); 2537 __ cmpl(rdx, Immediate(0xC0C0C0C0)); 2538 __ j(not_equal, &exit); 2539 __ incq(rax); 2540 2541 Operand r88 = Operand(r8, 8 * kIntSize); 2542 2543 // Test 31. 2544 __ movl(rdx, r88); // Sanity check. 2545 __ cmpl(rdx, Immediate(0x88888888)); 2546 __ j(not_equal, &exit); 2547 __ incq(rax); 2548 2549 __ movl(rdx, Operand(r88, -8 * kIntSize)); 2550 __ cmpl(rdx, Immediate(0x80808080)); 2551 __ j(not_equal, &exit); 2552 __ incq(rax); 2553 2554 __ movl(rdx, Operand(r88, 8 * kIntSize)); 2555 __ cmpl(rdx, Immediate(0x90909090)); 2556 __ j(not_equal, &exit); 2557 __ incq(rax); 2558 2559 __ movl(rdx, Operand(r88, -64 * kIntSize)); 2560 __ cmpl(rdx, Immediate(0x48484848)); 2561 __ j(not_equal, &exit); 2562 __ incq(rax); 2563 2564 __ movl(rdx, Operand(r88, 64 * kIntSize)); 2565 __ cmpl(rdx, Immediate(0xC8C8C8C8)); 2566 __ j(not_equal, &exit); 2567 __ incq(rax); 2568 2569 2570 Operand r864 = Operand(r8, 64 * kIntSize); 2571 2572 // Test 36. 2573 __ movl(rdx, r864); // Sanity check. 2574 __ cmpl(rdx, Immediate(0xC0C0C0C0)); 2575 __ j(not_equal, &exit); 2576 __ incq(rax); 2577 2578 __ movl(rdx, Operand(r864, -8 * kIntSize)); 2579 __ cmpl(rdx, Immediate(0xB8B8B8B8)); 2580 __ j(not_equal, &exit); 2581 __ incq(rax); 2582 2583 __ movl(rdx, Operand(r864, 8 * kIntSize)); 2584 __ cmpl(rdx, Immediate(0xC8C8C8C8)); 2585 __ j(not_equal, &exit); 2586 __ incq(rax); 2587 2588 __ movl(rdx, Operand(r864, -64 * kIntSize)); 2589 __ cmpl(rdx, Immediate(0x80808080)); 2590 __ j(not_equal, &exit); 2591 __ incq(rax); 2592 2593 __ movl(rdx, Operand(r864, 32 * kIntSize)); 2594 __ cmpl(rdx, Immediate(0xE0E0E0E0)); 2595 __ j(not_equal, &exit); 2596 __ incq(rax); 2597 2598 // 32-bit offset to 8-bit offset. 2599 __ movl(rdx, Operand(r864, -60 * kIntSize)); 2600 __ cmpl(rdx, Immediate(0x84848484)); 2601 __ j(not_equal, &exit); 2602 __ incq(rax); 2603 2604 __ movl(rdx, Operand(r864, 60 * kIntSize)); 2605 __ cmpl(rdx, Immediate(0xFCFCFCFC)); 2606 __ j(not_equal, &exit); 2607 __ incq(rax); 2608 2609 // Test unaligned offsets. 2610 2611 // Test 43. 2612 __ movl(rdx, Operand(r80, 2)); 2613 __ cmpl(rdx, Immediate(0x81818080)); 2614 __ j(not_equal, &exit); 2615 __ incq(rax); 2616 2617 __ movl(rdx, Operand(r80, -2)); 2618 __ cmpl(rdx, Immediate(0x80807F7F)); 2619 __ j(not_equal, &exit); 2620 __ incq(rax); 2621 2622 __ movl(rdx, Operand(r80, 126)); 2623 __ cmpl(rdx, Immediate(0xA0A09F9F)); 2624 __ j(not_equal, &exit); 2625 __ incq(rax); 2626 2627 __ movl(rdx, Operand(r80, -126)); 2628 __ cmpl(rdx, Immediate(0x61616060)); 2629 __ j(not_equal, &exit); 2630 __ incq(rax); 2631 2632 __ movl(rdx, Operand(r80, 254)); 2633 __ cmpl(rdx, Immediate(0xC0C0BFBF)); 2634 __ j(not_equal, &exit); 2635 __ incq(rax); 2636 2637 __ movl(rdx, Operand(r80, -254)); 2638 __ cmpl(rdx, Immediate(0x41414040)); 2639 __ j(not_equal, &exit); 2640 __ incq(rax); 2641 2642 // Success. 2643 2644 __ movl(rax, Immediate(0)); 2645 __ bind(&exit); 2646 __ lea(rsp, Operand(rbp, kPointerSize)); 2647 __ pop(rbp); 2648 __ pop(rbx); 2649 __ pop(r14); 2650 __ pop(r13); 2651 ExitCode(masm); 2652 __ ret(0); 2653 2654 2655 CodeDesc desc; 2656 masm->GetCode(&desc); 2657 // Call the function from C++. 2658 int result = FUNCTION_CAST<F0>(buffer)(); 2659 CHECK_EQ(0, result); 2660} 2661 2662 2663TEST(LoadAndStoreWithRepresentation) { 2664 v8::internal::V8::Initialize(NULL); 2665 2666 // Allocate an executable page of memory. 2667 size_t actual_size; 2668 byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, 2669 &actual_size, 2670 true)); 2671 CHECK(buffer); 2672 Isolate* isolate = CcTest::i_isolate(); 2673 HandleScope handles(isolate); 2674 MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); 2675 MacroAssembler* masm = &assembler; // Create a pointer for the __ macro. 2676 EntryCode(masm); 2677 __ subq(rsp, Immediate(1 * kPointerSize)); 2678 Label exit; 2679 2680 // Test 1. 2681 __ movq(rax, Immediate(1)); // Test number. 2682 __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0)); 2683 __ movq(rcx, Immediate(-1)); 2684 __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::UInteger8()); 2685 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); 2686 __ movl(rdx, Immediate(255)); 2687 __ cmpq(rcx, rdx); 2688 __ j(not_equal, &exit); 2689 __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::UInteger8()); 2690 __ cmpq(rcx, rdx); 2691 __ j(not_equal, &exit); 2692 2693 // Test 2. 2694 __ movq(rax, Immediate(2)); // Test number. 2695 __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0)); 2696 __ Set(rcx, V8_2PART_UINT64_C(0xdeadbeaf, 12345678)); 2697 __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Smi()); 2698 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); 2699 __ Set(rdx, V8_2PART_UINT64_C(0xdeadbeaf, 12345678)); 2700 __ cmpq(rcx, rdx); 2701 __ j(not_equal, &exit); 2702 __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Smi()); 2703 __ cmpq(rcx, rdx); 2704 __ j(not_equal, &exit); 2705 2706 // Test 3. 2707 __ movq(rax, Immediate(3)); // Test number. 2708 __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0)); 2709 __ movq(rcx, Immediate(-1)); 2710 __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer32()); 2711 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); 2712 __ movl(rdx, Immediate(-1)); 2713 __ cmpq(rcx, rdx); 2714 __ j(not_equal, &exit); 2715 __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer32()); 2716 __ cmpq(rcx, rdx); 2717 __ j(not_equal, &exit); 2718 2719 // Test 4. 2720 __ movq(rax, Immediate(4)); // Test number. 2721 __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0)); 2722 __ movl(rcx, Immediate(0x44332211)); 2723 __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::HeapObject()); 2724 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); 2725 __ movl(rdx, Immediate(0x44332211)); 2726 __ cmpq(rcx, rdx); 2727 __ j(not_equal, &exit); 2728 __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::HeapObject()); 2729 __ cmpq(rcx, rdx); 2730 __ j(not_equal, &exit); 2731 2732 // Test 5. 2733 __ movq(rax, Immediate(5)); // Test number. 2734 __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0)); 2735 __ Set(rcx, V8_2PART_UINT64_C(0x12345678, deadbeaf)); 2736 __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Tagged()); 2737 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); 2738 __ Set(rdx, V8_2PART_UINT64_C(0x12345678, deadbeaf)); 2739 __ cmpq(rcx, rdx); 2740 __ j(not_equal, &exit); 2741 __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Tagged()); 2742 __ cmpq(rcx, rdx); 2743 __ j(not_equal, &exit); 2744 2745 // Test 6. 2746 __ movq(rax, Immediate(6)); // Test number. 2747 __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0)); 2748 __ Set(rcx, V8_2PART_UINT64_C(0x11223344, 55667788)); 2749 __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::External()); 2750 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); 2751 __ Set(rdx, V8_2PART_UINT64_C(0x11223344, 55667788)); 2752 __ cmpq(rcx, rdx); 2753 __ j(not_equal, &exit); 2754 __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::External()); 2755 __ cmpq(rcx, rdx); 2756 __ j(not_equal, &exit); 2757 2758 // Test 7. 2759 __ movq(rax, Immediate(7)); // Test number. 2760 __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0)); 2761 __ movq(rcx, Immediate(-1)); 2762 __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer8()); 2763 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); 2764 __ movl(rdx, Immediate(255)); 2765 __ cmpq(rcx, rdx); 2766 __ j(not_equal, &exit); 2767 __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer8()); 2768 __ movq(rcx, Immediate(-1)); 2769 __ cmpq(rcx, rdx); 2770 __ j(not_equal, &exit); 2771 2772 // Test 8. 2773 __ movq(rax, Immediate(8)); // Test number. 2774 __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0)); 2775 __ movq(rcx, Immediate(-1)); 2776 __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::Integer16()); 2777 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); 2778 __ movl(rdx, Immediate(65535)); 2779 __ cmpq(rcx, rdx); 2780 __ j(not_equal, &exit); 2781 __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::Integer16()); 2782 __ movq(rcx, Immediate(-1)); 2783 __ cmpq(rcx, rdx); 2784 __ j(not_equal, &exit); 2785 2786 // Test 9. 2787 __ movq(rax, Immediate(9)); // Test number. 2788 __ movq(Operand(rsp, 0 * kPointerSize), Immediate(0)); 2789 __ movq(rcx, Immediate(-1)); 2790 __ Store(Operand(rsp, 0 * kPointerSize), rcx, Representation::UInteger16()); 2791 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); 2792 __ movl(rdx, Immediate(65535)); 2793 __ cmpq(rcx, rdx); 2794 __ j(not_equal, &exit); 2795 __ Load(rdx, Operand(rsp, 0 * kPointerSize), Representation::UInteger16()); 2796 __ cmpq(rcx, rdx); 2797 __ j(not_equal, &exit); 2798 2799 __ xor_(rax, rax); // Success. 2800 __ bind(&exit); 2801 __ addq(rsp, Immediate(1 * kPointerSize)); 2802 ExitCode(masm); 2803 __ ret(0); 2804 2805 CodeDesc desc; 2806 masm->GetCode(&desc); 2807 // Call the function from C++. 2808 int result = FUNCTION_CAST<F0>(buffer)(); 2809 CHECK_EQ(0, result); 2810} 2811 2812 2813#undef __ 2814