Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/x64/code-stubs-x64.cc

Issue 6697023: Merge 6800:7180 from the bleeding edge branch to the experimental/gc branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | src/x64/codegen-x64.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 28 matching lines...) Expand all
39 #define __ ACCESS_MASM(masm) 39 #define __ ACCESS_MASM(masm)
40 40
41 void ToNumberStub::Generate(MacroAssembler* masm) { 41 void ToNumberStub::Generate(MacroAssembler* masm) {
42 // The ToNumber stub takes one argument in eax. 42 // The ToNumber stub takes one argument in eax.
43 NearLabel check_heap_number, call_builtin; 43 NearLabel check_heap_number, call_builtin;
44 __ SmiTest(rax); 44 __ SmiTest(rax);
45 __ j(not_zero, &check_heap_number); 45 __ j(not_zero, &check_heap_number);
46 __ Ret(); 46 __ Ret();
47 47
48 __ bind(&check_heap_number); 48 __ bind(&check_heap_number);
49 __ Move(rbx, Factory::heap_number_map()); 49 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
50 __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); 50 Heap::kHeapNumberMapRootIndex);
51 __ j(not_equal, &call_builtin); 51 __ j(not_equal, &call_builtin);
52 __ Ret(); 52 __ Ret();
53 53
54 __ bind(&call_builtin); 54 __ bind(&call_builtin);
55 __ pop(rcx); // Pop return address. 55 __ pop(rcx); // Pop return address.
56 __ push(rax); 56 __ push(rax);
57 __ push(rcx); // Push return address. 57 __ push(rcx); // Push return address.
58 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); 58 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
59 } 59 }
60 60
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 97
98 // Return and remove the on-stack parameter. 98 // Return and remove the on-stack parameter.
99 __ ret(1 * kPointerSize); 99 __ ret(1 * kPointerSize);
100 100
101 // Create a new closure through the slower runtime call. 101 // Create a new closure through the slower runtime call.
102 __ bind(&gc); 102 __ bind(&gc);
103 __ pop(rcx); // Temporarily remove return address. 103 __ pop(rcx); // Temporarily remove return address.
104 __ pop(rdx); 104 __ pop(rdx);
105 __ push(rsi); 105 __ push(rsi);
106 __ push(rdx); 106 __ push(rdx);
107 __ Push(Factory::false_value()); 107 __ PushRoot(Heap::kFalseValueRootIndex);
108 __ push(rcx); // Restore return address. 108 __ push(rcx); // Restore return address.
109 __ TailCallRuntime(Runtime::kNewClosure, 3, 1); 109 __ TailCallRuntime(Runtime::kNewClosure, 3, 1);
110 } 110 }
111 111
112 112
113 void FastNewContextStub::Generate(MacroAssembler* masm) { 113 void FastNewContextStub::Generate(MacroAssembler* masm) {
114 // Try to allocate the context in new space. 114 // Try to allocate the context in new space.
115 Label gc; 115 Label gc;
116 int length = slots_ + Context::MIN_CONTEXT_SLOTS; 116 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
117 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, 117 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize,
(...skipping 1250 matching lines...) Expand 10 before | Expand all | Expand 10 after
1368 } 1368 }
1369 // No fall-through from this generated code. 1369 // No fall-through from this generated code.
1370 if (FLAG_debug_code) { 1370 if (FLAG_debug_code) {
1371 __ Abort("Unexpected fall-through in " 1371 __ Abort("Unexpected fall-through in "
1372 "TypeRecordingBinaryStub::GenerateFloatingPointCode."); 1372 "TypeRecordingBinaryStub::GenerateFloatingPointCode.");
1373 } 1373 }
1374 } 1374 }
1375 1375
1376 1376
1377 void TypeRecordingBinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) { 1377 void TypeRecordingBinaryOpStub::GenerateStringAddCode(MacroAssembler* masm) {
1378 ASSERT(op_ == Token::ADD);
1379 NearLabel left_not_string, call_runtime;
1380
1381 // Registers containing left and right operands respectively.
1382 Register left = rdx;
1383 Register right = rax;
1384
1385 // Test if left operand is a string.
1386 __ JumpIfSmi(left, &left_not_string);
1387 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx);
1388 __ j(above_equal, &left_not_string);
1389 StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB);
1378 GenerateRegisterArgsPush(masm); 1390 GenerateRegisterArgsPush(masm);
1379 // Registers containing left and right operands respectively. 1391 __ TailCallStub(&string_add_left_stub);
1380 Register lhs = rdx;
1381 Register rhs = rax;
1382 1392
1383 // Test for string arguments before calling runtime. 1393 // Left operand is not a string, test right.
1384 Label not_strings, both_strings, not_string1, string1, string1_smi2; 1394 __ bind(&left_not_string);
1395 __ JumpIfSmi(right, &call_runtime);
1396 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx);
1397 __ j(above_equal, &call_runtime);
1385 1398
1386 __ JumpIfNotString(lhs, r8, &not_string1); 1399 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
1400 GenerateRegisterArgsPush(masm);
1401 __ TailCallStub(&string_add_right_stub);
1387 1402
1388 // First argument is a a string, test second.
1389 __ JumpIfSmi(rhs, &string1_smi2);
1390 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, r9);
1391 __ j(above_equal, &string1);
1392
1393 // First and second argument are strings.
1394 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
1395 __ TailCallStub(&string_add_stub);
1396
1397 __ bind(&string1_smi2);
1398 // First argument is a string, second is a smi. Try to lookup the number
1399 // string for the smi in the number string cache.
1400 NumberToStringStub::GenerateLookupNumberStringCache(
1401 masm, rhs, rbx, rcx, r8, true, &string1);
1402
1403 // Replace second argument on stack and tailcall string add stub to make
1404 // the result.
1405 __ movq(Operand(rsp, 1 * kPointerSize), rbx);
1406 __ TailCallStub(&string_add_stub);
1407
1408 // Only first argument is a string.
1409 __ bind(&string1);
1410 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
1411
1412 // First argument was not a string, test second.
1413 __ bind(&not_string1);
1414 __ JumpIfNotString(rhs, rhs, &not_strings);
1415
1416 // Only second argument is a string.
1417 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
1418
1419 __ bind(&not_strings);
1420 // Neither argument is a string. 1403 // Neither argument is a string.
1421 // Pop arguments, because CallRuntimeCode wants to push them again. 1404 __ bind(&call_runtime);
1422 __ pop(rcx);
1423 __ pop(rax);
1424 __ pop(rdx);
1425 __ push(rcx);
1426 } 1405 }
1427 1406
1428 1407
1429 void TypeRecordingBinaryOpStub::GenerateCallRuntimeCode(MacroAssembler* masm) { 1408 void TypeRecordingBinaryOpStub::GenerateCallRuntimeCode(MacroAssembler* masm) {
1430 GenerateRegisterArgsPush(masm); 1409 GenerateRegisterArgsPush(masm);
1431 switch (op_) { 1410 switch (op_) {
1432 case Token::ADD: 1411 case Token::ADD:
1433 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 1412 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
1434 break; 1413 break;
1435 case Token::SUB: 1414 case Token::SUB:
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1472 Label not_smi; 1451 Label not_smi;
1473 1452
1474 GenerateSmiCode(masm, &not_smi, NO_HEAPNUMBER_RESULTS); 1453 GenerateSmiCode(masm, &not_smi, NO_HEAPNUMBER_RESULTS);
1475 1454
1476 __ bind(&not_smi); 1455 __ bind(&not_smi);
1477 GenerateTypeTransition(masm); 1456 GenerateTypeTransition(masm);
1478 } 1457 }
1479 1458
1480 1459
1481 void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) { 1460 void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
1461 ASSERT(operands_type_ == TRBinaryOpIC::STRING);
1482 ASSERT(op_ == Token::ADD); 1462 ASSERT(op_ == Token::ADD);
1483 GenerateStringAddCode(masm); 1463 GenerateStringAddCode(masm);
1484 1464 // Try to add arguments as strings, otherwise, transition to the generic
1465 // TRBinaryOpIC type.
1485 GenerateTypeTransition(masm); 1466 GenerateTypeTransition(masm);
1486 } 1467 }
1487 1468
1488 1469
1489 void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 1470 void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
1490 Label gc_required, not_number; 1471 Label gc_required, not_number;
1491 GenerateFloatingPointCode(masm, &gc_required, &not_number); 1472 GenerateFloatingPointCode(masm, &gc_required, &not_number);
1492 1473
1493 __ bind(&not_number); 1474 __ bind(&not_number);
1494 GenerateTypeTransition(masm); 1475 GenerateTypeTransition(masm);
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1557 1538
1558 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 1539 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
1559 __ pop(rcx); 1540 __ pop(rcx);
1560 __ push(rdx); 1541 __ push(rdx);
1561 __ push(rax); 1542 __ push(rax);
1562 __ push(rcx); 1543 __ push(rcx);
1563 } 1544 }
1564 1545
1565 1546
1566 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { 1547 void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
1567 // Input on stack: 1548 // TAGGED case:
1568 // rsp[8]: argument (should be number). 1549 // Input:
1569 // rsp[0]: return address. 1550 // rsp[8]: argument (should be number).
1551 // rsp[0]: return address.
1552 // Output:
1553 // rax: tagged double result.
1554 // UNTAGGED case:
1555 // Input::
1556 // rsp[0]: return address.
1557 // xmm1: untagged double input argument
1558 // Output:
1559 // xmm1: untagged double result.
1560
1570 Label runtime_call; 1561 Label runtime_call;
1571 Label runtime_call_clear_stack; 1562 Label runtime_call_clear_stack;
1572 Label input_not_smi; 1563 Label skip_cache;
1573 NearLabel loaded; 1564 const bool tagged = (argument_type_ == TAGGED);
1574 // Test that rax is a number. 1565 if (tagged) {
1575 __ movq(rax, Operand(rsp, kPointerSize)); 1566 NearLabel input_not_smi;
1576 __ JumpIfNotSmi(rax, &input_not_smi); 1567 NearLabel loaded;
1577 // Input is a smi. Untag and load it onto the FPU stack. 1568 // Test that rax is a number.
1578 // Then load the bits of the double into rbx. 1569 __ movq(rax, Operand(rsp, kPointerSize));
1579 __ SmiToInteger32(rax, rax); 1570 __ JumpIfNotSmi(rax, &input_not_smi);
1580 __ subq(rsp, Immediate(kPointerSize)); 1571 // Input is a smi. Untag and load it onto the FPU stack.
1581 __ cvtlsi2sd(xmm1, rax); 1572 // Then load the bits of the double into rbx.
1582 __ movsd(Operand(rsp, 0), xmm1); 1573 __ SmiToInteger32(rax, rax);
1583 __ movq(rbx, xmm1); 1574 __ subq(rsp, Immediate(kDoubleSize));
1584 __ movq(rdx, xmm1); 1575 __ cvtlsi2sd(xmm1, rax);
1585 __ fld_d(Operand(rsp, 0)); 1576 __ movsd(Operand(rsp, 0), xmm1);
1586 __ addq(rsp, Immediate(kPointerSize)); 1577 __ movq(rbx, xmm1);
1587 __ jmp(&loaded); 1578 __ movq(rdx, xmm1);
1579 __ fld_d(Operand(rsp, 0));
1580 __ addq(rsp, Immediate(kDoubleSize));
1581 __ jmp(&loaded);
1588 1582
1589 __ bind(&input_not_smi); 1583 __ bind(&input_not_smi);
1590 // Check if input is a HeapNumber. 1584 // Check if input is a HeapNumber.
1591 __ Move(rbx, Factory::heap_number_map()); 1585 __ LoadRoot(rbx, Heap::kHeapNumberMapRootIndex);
1592 __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); 1586 __ cmpq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
1593 __ j(not_equal, &runtime_call); 1587 __ j(not_equal, &runtime_call);
1594 // Input is a HeapNumber. Push it on the FPU stack and load its 1588 // Input is a HeapNumber. Push it on the FPU stack and load its
1595 // bits into rbx. 1589 // bits into rbx.
1596 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); 1590 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
1597 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); 1591 __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset));
1598 __ movq(rdx, rbx); 1592 __ movq(rdx, rbx);
1599 __ bind(&loaded); 1593
1600 // ST[0] == double value 1594 __ bind(&loaded);
1595 } else { // UNTAGGED.
1596 __ movq(rbx, xmm1);
1597 __ movq(rdx, xmm1);
1598 }
1599
1600 // ST[0] == double value, if TAGGED.
1601 // rbx = bits of double value. 1601 // rbx = bits of double value.
1602 // rdx = also bits of double value. 1602 // rdx = also bits of double value.
1603 // Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic): 1603 // Compute hash (h is 32 bits, bits are 64 and the shifts are arithmetic):
1604 // h = h0 = bits ^ (bits >> 32); 1604 // h = h0 = bits ^ (bits >> 32);
1605 // h ^= h >> 16; 1605 // h ^= h >> 16;
1606 // h ^= h >> 8; 1606 // h ^= h >> 8;
1607 // h = h & (cacheSize - 1); 1607 // h = h & (cacheSize - 1);
1608 // or h = (h0 ^ (h0 >> 8) ^ (h0 >> 16) ^ (h0 >> 24)) & (cacheSize - 1) 1608 // or h = (h0 ^ (h0 >> 8) ^ (h0 >> 16) ^ (h0 >> 24)) & (cacheSize - 1)
1609 __ sar(rdx, Immediate(32)); 1609 __ sar(rdx, Immediate(32));
1610 __ xorl(rdx, rbx); 1610 __ xorl(rdx, rbx);
(...skipping 11 matching lines...) Expand all
1622 1622
1623 // ST[0] == double value. 1623 // ST[0] == double value.
1624 // rbx = bits of double value. 1624 // rbx = bits of double value.
1625 // rcx = TranscendentalCache::hash(double value). 1625 // rcx = TranscendentalCache::hash(double value).
1626 __ movq(rax, ExternalReference::transcendental_cache_array_address()); 1626 __ movq(rax, ExternalReference::transcendental_cache_array_address());
1627 // rax points to cache array. 1627 // rax points to cache array.
1628 __ movq(rax, Operand(rax, type_ * sizeof(TranscendentalCache::caches_[0]))); 1628 __ movq(rax, Operand(rax, type_ * sizeof(TranscendentalCache::caches_[0])));
1629 // rax points to the cache for the type type_. 1629 // rax points to the cache for the type type_.
1630 // If NULL, the cache hasn't been initialized yet, so go through runtime. 1630 // If NULL, the cache hasn't been initialized yet, so go through runtime.
1631 __ testq(rax, rax); 1631 __ testq(rax, rax);
1632 __ j(zero, &runtime_call_clear_stack); 1632 __ j(zero, &runtime_call_clear_stack); // Only clears stack if TAGGED.
1633 #ifdef DEBUG 1633 #ifdef DEBUG
1634 // Check that the layout of cache elements match expectations. 1634 // Check that the layout of cache elements match expectations.
1635 { // NOLINT - doesn't like a single brace on a line. 1635 { // NOLINT - doesn't like a single brace on a line.
1636 TranscendentalCache::Element test_elem[2]; 1636 TranscendentalCache::Element test_elem[2];
1637 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 1637 char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
1638 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 1638 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
1639 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 1639 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
1640 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 1640 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
1641 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 1641 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
1642 // Two uint_32's and a pointer per element. 1642 // Two uint_32's and a pointer per element.
1643 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start)); 1643 CHECK_EQ(16, static_cast<int>(elem2_start - elem_start));
1644 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start)); 1644 CHECK_EQ(0, static_cast<int>(elem_in0 - elem_start));
1645 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start)); 1645 CHECK_EQ(kIntSize, static_cast<int>(elem_in1 - elem_start));
1646 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start)); 1646 CHECK_EQ(2 * kIntSize, static_cast<int>(elem_out - elem_start));
1647 } 1647 }
1648 #endif 1648 #endif
1649 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16]. 1649 // Find the address of the rcx'th entry in the cache, i.e., &rax[rcx*16].
1650 __ addl(rcx, rcx); 1650 __ addl(rcx, rcx);
1651 __ lea(rcx, Operand(rax, rcx, times_8, 0)); 1651 __ lea(rcx, Operand(rax, rcx, times_8, 0));
1652 // Check if cache matches: Double value is stored in uint32_t[2] array. 1652 // Check if cache matches: Double value is stored in uint32_t[2] array.
1653 NearLabel cache_miss; 1653 NearLabel cache_miss;
1654 __ cmpq(rbx, Operand(rcx, 0)); 1654 __ cmpq(rbx, Operand(rcx, 0));
1655 __ j(not_equal, &cache_miss); 1655 __ j(not_equal, &cache_miss);
1656 // Cache hit! 1656 // Cache hit!
1657 __ movq(rax, Operand(rcx, 2 * kIntSize)); 1657 __ movq(rax, Operand(rcx, 2 * kIntSize));
1658 __ fstp(0); // Clear FPU stack. 1658 if (tagged) {
1659 __ ret(kPointerSize); 1659 __ fstp(0); // Clear FPU stack.
1660 __ ret(kPointerSize);
1661 } else { // UNTAGGED.
1662 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1663 __ Ret();
1664 }
1660 1665
1661 __ bind(&cache_miss); 1666 __ bind(&cache_miss);
1662 // Update cache with new value. 1667 // Update cache with new value.
1663 Label nan_result; 1668 if (tagged) {
1664 GenerateOperation(masm, &nan_result);
1665 __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack); 1669 __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack);
1670 } else { // UNTAGGED.
1671 __ AllocateHeapNumber(rax, rdi, &skip_cache);
1672 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
1673 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
1674 }
1675 GenerateOperation(masm);
1666 __ movq(Operand(rcx, 0), rbx); 1676 __ movq(Operand(rcx, 0), rbx);
1667 __ movq(Operand(rcx, 2 * kIntSize), rax); 1677 __ movq(Operand(rcx, 2 * kIntSize), rax);
1668 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); 1678 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
1669 __ ret(kPointerSize); 1679 if (tagged) {
1680 __ ret(kPointerSize);
1681 } else { // UNTAGGED.
1682 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1683 __ Ret();
1670 1684
1671 __ bind(&runtime_call_clear_stack); 1685 // Skip cache and return answer directly, only in untagged case.
1672 __ fstp(0); 1686 __ bind(&skip_cache);
1673 __ bind(&runtime_call); 1687 __ subq(rsp, Immediate(kDoubleSize));
1674 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); 1688 __ movsd(Operand(rsp, 0), xmm1);
1689 __ fld_d(Operand(rsp, 0));
1690 GenerateOperation(masm);
1691 __ fstp_d(Operand(rsp, 0));
1692 __ movsd(xmm1, Operand(rsp, 0));
1693 __ addq(rsp, Immediate(kDoubleSize));
1694 // We return the value in xmm1 without adding it to the cache, but
1695 // we cause a scavenging GC so that future allocations will succeed.
1696 __ EnterInternalFrame();
1697 // Allocate an unused object bigger than a HeapNumber.
1698 __ Push(Smi::FromInt(2 * kDoubleSize));
1699 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
1700 __ LeaveInternalFrame();
1701 __ Ret();
1702 }
1675 1703
1676 __ bind(&nan_result); 1704 // Call runtime, doing whatever allocation and cleanup is necessary.
1677 __ fstp(0); // Remove argument from FPU stack. 1705 if (tagged) {
1678 __ LoadRoot(rax, Heap::kNanValueRootIndex); 1706 __ bind(&runtime_call_clear_stack);
1679 __ movq(Operand(rcx, 0), rbx); 1707 __ fstp(0);
1680 __ movq(Operand(rcx, 2 * kIntSize), rax); 1708 __ bind(&runtime_call);
1681 __ ret(kPointerSize); 1709 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
1710 } else { // UNTAGGED.
1711 __ bind(&runtime_call_clear_stack);
1712 __ bind(&runtime_call);
1713 __ AllocateHeapNumber(rax, rdi, &skip_cache);
1714 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
1715 __ EnterInternalFrame();
1716 __ push(rax);
1717 __ CallRuntime(RuntimeFunction(), 1);
1718 __ LeaveInternalFrame();
1719 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
1720 __ Ret();
1721 }
1682 } 1722 }
1683 1723
1684 1724
1685 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { 1725 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
1686 switch (type_) { 1726 switch (type_) {
1687 // Add more cases when necessary. 1727 // Add more cases when necessary.
1688 case TranscendentalCache::SIN: return Runtime::kMath_sin; 1728 case TranscendentalCache::SIN: return Runtime::kMath_sin;
1689 case TranscendentalCache::COS: return Runtime::kMath_cos; 1729 case TranscendentalCache::COS: return Runtime::kMath_cos;
1690 case TranscendentalCache::LOG: return Runtime::kMath_log; 1730 case TranscendentalCache::LOG: return Runtime::kMath_log;
1691 default: 1731 default:
1692 UNIMPLEMENTED(); 1732 UNIMPLEMENTED();
1693 return Runtime::kAbort; 1733 return Runtime::kAbort;
1694 } 1734 }
1695 } 1735 }
1696 1736
1697 1737
1698 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm, 1738 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
1699 Label* on_nan_result) {
1700 // Registers: 1739 // Registers:
1740 // rax: Newly allocated HeapNumber, which must be preserved.
1701 // rbx: Bits of input double. Must be preserved. 1741 // rbx: Bits of input double. Must be preserved.
1702 // rcx: Pointer to cache entry. Must be preserved. 1742 // rcx: Pointer to cache entry. Must be preserved.
1703 // st(0): Input double 1743 // st(0): Input double
1704 Label done; 1744 Label done;
1705 if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { 1745 if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) {
1706 // Both fsin and fcos require arguments in the range +/-2^63 and 1746 // Both fsin and fcos require arguments in the range +/-2^63 and
1707 // return NaN for infinities and NaN. They can share all code except 1747 // return NaN for infinities and NaN. They can share all code except
1708 // the actual fsin/fcos operation. 1748 // the actual fsin/fcos operation.
1709 Label in_range; 1749 Label in_range;
1710 // If argument is outside the range -2^63..2^63, fsin/cos doesn't 1750 // If argument is outside the range -2^63..2^63, fsin/cos doesn't
1711 // work. We must reduce it to the appropriate range. 1751 // work. We must reduce it to the appropriate range.
1712 __ movq(rdi, rbx); 1752 __ movq(rdi, rbx);
1713 // Move exponent and sign bits to low bits. 1753 // Move exponent and sign bits to low bits.
1714 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); 1754 __ shr(rdi, Immediate(HeapNumber::kMantissaBits));
1715 // Remove sign bit. 1755 // Remove sign bit.
1716 __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); 1756 __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1));
1717 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); 1757 int supported_exponent_limit = (63 + HeapNumber::kExponentBias);
1718 __ cmpl(rdi, Immediate(supported_exponent_limit)); 1758 __ cmpl(rdi, Immediate(supported_exponent_limit));
1719 __ j(below, &in_range); 1759 __ j(below, &in_range);
1720 // Check for infinity and NaN. Both return NaN for sin. 1760 // Check for infinity and NaN. Both return NaN for sin.
1721 __ cmpl(rdi, Immediate(0x7ff)); 1761 __ cmpl(rdi, Immediate(0x7ff));
1722 __ j(equal, on_nan_result); 1762 NearLabel non_nan_result;
1763 __ j(not_equal, &non_nan_result);
1764 // Input is +/-Infinity or NaN. Result is NaN.
1765 __ fstp(0);
1766 __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex);
1767 __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset));
1768 __ jmp(&done);
1769
1770 __ bind(&non_nan_result);
1723 1771
1724 // Use fpmod to restrict argument to the range +/-2*PI. 1772 // Use fpmod to restrict argument to the range +/-2*PI.
1773 __ movq(rdi, rax); // Save rax before using fnstsw_ax.
1725 __ fldpi(); 1774 __ fldpi();
1726 __ fadd(0); 1775 __ fadd(0);
1727 __ fld(1); 1776 __ fld(1);
1728 // FPU Stack: input, 2*pi, input. 1777 // FPU Stack: input, 2*pi, input.
1729 { 1778 {
1730 Label no_exceptions; 1779 Label no_exceptions;
1731 __ fwait(); 1780 __ fwait();
1732 __ fnstsw_ax(); 1781 __ fnstsw_ax();
1733 // Clear if Illegal Operand or Zero Division exceptions are set. 1782 // Clear if Illegal Operand or Zero Division exceptions are set.
1734 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. 1783 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word.
(...skipping 12 matching lines...) Expand all
1747 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. 1796 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word.
1748 // If C2 is set, computation only has partial result. Loop to 1797 // If C2 is set, computation only has partial result. Loop to
1749 // continue computation. 1798 // continue computation.
1750 __ j(not_zero, &partial_remainder_loop); 1799 __ j(not_zero, &partial_remainder_loop);
1751 } 1800 }
1752 // FPU Stack: input, 2*pi, input % 2*pi 1801 // FPU Stack: input, 2*pi, input % 2*pi
1753 __ fstp(2); 1802 __ fstp(2);
1754 // FPU Stack: input % 2*pi, 2*pi, 1803 // FPU Stack: input % 2*pi, 2*pi,
1755 __ fstp(0); 1804 __ fstp(0);
1756 // FPU Stack: input % 2*pi 1805 // FPU Stack: input % 2*pi
1806 __ movq(rax, rdi); // Restore rax, pointer to the new HeapNumber.
1757 __ bind(&in_range); 1807 __ bind(&in_range);
1758 switch (type_) { 1808 switch (type_) {
1759 case TranscendentalCache::SIN: 1809 case TranscendentalCache::SIN:
1760 __ fsin(); 1810 __ fsin();
1761 break; 1811 break;
1762 case TranscendentalCache::COS: 1812 case TranscendentalCache::COS:
1763 __ fcos(); 1813 __ fcos();
1764 break; 1814 break;
1765 default: 1815 default:
1766 UNREACHABLE(); 1816 UNREACHABLE();
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
1999 } 2049 }
2000 __ SmiNeg(rax, rax, &done); 2050 __ SmiNeg(rax, rax, &done);
2001 __ jmp(&slow); // zero, if not handled above, and Smi::kMinValue. 2051 __ jmp(&slow); // zero, if not handled above, and Smi::kMinValue.
2002 2052
2003 // Try floating point case. 2053 // Try floating point case.
2004 __ bind(&try_float); 2054 __ bind(&try_float);
2005 } else if (FLAG_debug_code) { 2055 } else if (FLAG_debug_code) {
2006 __ AbortIfSmi(rax); 2056 __ AbortIfSmi(rax);
2007 } 2057 }
2008 2058
2009 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); 2059 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
2010 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); 2060 Heap::kHeapNumberMapRootIndex);
2011 __ j(not_equal, &slow); 2061 __ j(not_equal, &slow);
2012 // Operand is a float, negate its value by flipping sign bit. 2062 // Operand is a float, negate its value by flipping sign bit.
2013 __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset)); 2063 __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset));
2014 __ movq(kScratchRegister, Immediate(0x01)); 2064 __ movq(kScratchRegister, Immediate(0x01));
2015 __ shl(kScratchRegister, Immediate(63)); 2065 __ shl(kScratchRegister, Immediate(63));
2016 __ xor_(rdx, kScratchRegister); // Flip sign. 2066 __ xor_(rdx, kScratchRegister); // Flip sign.
2017 // rdx is value to store. 2067 // rdx is value to store.
2018 if (overwrite_ == UNARY_OVERWRITE) { 2068 if (overwrite_ == UNARY_OVERWRITE) {
2019 __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx); 2069 __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx);
2020 } else { 2070 } else {
2021 __ AllocateHeapNumber(rcx, rbx, &slow); 2071 __ AllocateHeapNumber(rcx, rbx, &slow);
2022 // rcx: allocated 'empty' number 2072 // rcx: allocated 'empty' number
2023 __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx); 2073 __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx);
2024 __ movq(rax, rcx); 2074 __ movq(rax, rcx);
2025 } 2075 }
2026 } else if (op_ == Token::BIT_NOT) { 2076 } else if (op_ == Token::BIT_NOT) {
2027 if (include_smi_code_) { 2077 if (include_smi_code_) {
2028 Label try_float; 2078 Label try_float;
2029 __ JumpIfNotSmi(rax, &try_float); 2079 __ JumpIfNotSmi(rax, &try_float);
2030 __ SmiNot(rax, rax); 2080 __ SmiNot(rax, rax);
2031 __ jmp(&done); 2081 __ jmp(&done);
2032 // Try floating point case. 2082 // Try floating point case.
2033 __ bind(&try_float); 2083 __ bind(&try_float);
2034 } else if (FLAG_debug_code) { 2084 } else if (FLAG_debug_code) {
2035 __ AbortIfSmi(rax); 2085 __ AbortIfSmi(rax);
2036 } 2086 }
2037 2087
2038 // Check if the operand is a heap number. 2088 // Check if the operand is a heap number.
2039 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); 2089 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
2040 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); 2090 Heap::kHeapNumberMapRootIndex);
2041 __ j(not_equal, &slow); 2091 __ j(not_equal, &slow);
2042 2092
2043 // Convert the heap number in rax to an untagged integer in rcx. 2093 // Convert the heap number in rax to an untagged integer in rcx.
2044 IntegerConvert(masm, rax, rax); 2094 IntegerConvert(masm, rax, rax);
2045 2095
2046 // Do the bitwise operation and smi tag the result. 2096 // Do the bitwise operation and smi tag the result.
2047 __ notl(rax); 2097 __ notl(rax);
2048 __ Integer32ToSmi(rax, rax); 2098 __ Integer32ToSmi(rax, rax);
2049 } 2099 }
2050 2100
(...skipping 12 matching lines...) Expand all
2063 break; 2113 break;
2064 case Token::BIT_NOT: 2114 case Token::BIT_NOT:
2065 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 2115 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
2066 break; 2116 break;
2067 default: 2117 default:
2068 UNREACHABLE(); 2118 UNREACHABLE();
2069 } 2119 }
2070 } 2120 }
2071 2121
2072 2122
2123 void MathPowStub::Generate(MacroAssembler* masm) {
2124 // Registers are used as follows:
2125 // rdx = base
2126 // rax = exponent
2127 // rcx = temporary, result
2128
2129 Label allocate_return, call_runtime;
2130
2131 // Load input parameters.
2132 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
2133 __ movq(rax, Operand(rsp, 1 * kPointerSize));
2134
2135 // Save 1 in xmm3 - we need this several times later on.
2136 __ movl(rcx, Immediate(1));
2137 __ cvtlsi2sd(xmm3, rcx);
2138
2139 Label exponent_nonsmi;
2140 Label base_nonsmi;
2141 // If the exponent is a heap number go to that specific case.
2142 __ JumpIfNotSmi(rax, &exponent_nonsmi);
2143 __ JumpIfNotSmi(rdx, &base_nonsmi);
2144
2145 // Optimized version when both exponent and base are smis.
2146 Label powi;
2147 __ SmiToInteger32(rdx, rdx);
2148 __ cvtlsi2sd(xmm0, rdx);
2149 __ jmp(&powi);
2150 // Exponent is a smi and base is a heapnumber.
2151 __ bind(&base_nonsmi);
2152 __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset),
2153 Heap::kHeapNumberMapRootIndex);
2154 __ j(not_equal, &call_runtime);
2155
2156 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
2157
2158 // Optimized version of pow if exponent is a smi.
2159 // xmm0 contains the base.
2160 __ bind(&powi);
2161 __ SmiToInteger32(rax, rax);
2162
2163 // Save exponent in base as we need to check if exponent is negative later.
2164 // We know that base and exponent are in different registers.
2165 __ movq(rdx, rax);
2166
2167 // Get absolute value of exponent.
2168 NearLabel no_neg;
2169 __ cmpl(rax, Immediate(0));
2170 __ j(greater_equal, &no_neg);
2171 __ negl(rax);
2172 __ bind(&no_neg);
2173
2174 // Load xmm1 with 1.
2175 __ movsd(xmm1, xmm3);
2176 NearLabel while_true;
2177 NearLabel no_multiply;
2178
2179 __ bind(&while_true);
2180 __ shrl(rax, Immediate(1));
2181 __ j(not_carry, &no_multiply);
2182 __ mulsd(xmm1, xmm0);
2183 __ bind(&no_multiply);
2184 __ mulsd(xmm0, xmm0);
2185 __ j(not_zero, &while_true);
2186
2187 // Base has the original value of the exponent - if the exponent is
2188 // negative return 1/result.
2189 __ testl(rdx, rdx);
2190 __ j(positive, &allocate_return);
2191 // Special case if xmm1 has reached infinity.
2192 __ divsd(xmm3, xmm1);
2193 __ movsd(xmm1, xmm3);
2194 __ xorpd(xmm0, xmm0);
2195 __ ucomisd(xmm0, xmm1);
2196 __ j(equal, &call_runtime);
2197
2198 __ jmp(&allocate_return);
2199
2200 // Exponent (or both) is a heapnumber - no matter what we should now work
2201 // on doubles.
2202 __ bind(&exponent_nonsmi);
2203 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
2204 Heap::kHeapNumberMapRootIndex);
2205 __ j(not_equal, &call_runtime);
2206 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
2207 // Test if exponent is nan.
2208 __ ucomisd(xmm1, xmm1);
2209 __ j(parity_even, &call_runtime);
2210
2211 NearLabel base_not_smi;
2212 NearLabel handle_special_cases;
2213 __ JumpIfNotSmi(rdx, &base_not_smi);
2214 __ SmiToInteger32(rdx, rdx);
2215 __ cvtlsi2sd(xmm0, rdx);
2216 __ jmp(&handle_special_cases);
2217
2218 __ bind(&base_not_smi);
2219 __ CompareRoot(FieldOperand(rdx, HeapObject::kMapOffset),
2220 Heap::kHeapNumberMapRootIndex);
2221 __ j(not_equal, &call_runtime);
2222 __ movl(rcx, FieldOperand(rdx, HeapNumber::kExponentOffset));
2223 __ andl(rcx, Immediate(HeapNumber::kExponentMask));
2224 __ cmpl(rcx, Immediate(HeapNumber::kExponentMask));
2225 // base is NaN or +/-Infinity
2226 __ j(greater_equal, &call_runtime);
2227 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
2228
2229 // base is in xmm0 and exponent is in xmm1.
2230 __ bind(&handle_special_cases);
2231 NearLabel not_minus_half;
2232 // Test for -0.5.
2233 // Load xmm2 with -0.5.
2234 __ movq(rcx, V8_UINT64_C(0xBFE0000000000000), RelocInfo::NONE);
2235 __ movq(xmm2, rcx);
2236 // xmm2 now has -0.5.
2237 __ ucomisd(xmm2, xmm1);
2238 __ j(not_equal, &not_minus_half);
2239
2240 // Calculates reciprocal of square root.
2241 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
2242 __ xorpd(xmm1, xmm1);
2243 __ addsd(xmm1, xmm0);
2244 __ sqrtsd(xmm1, xmm1);
2245 __ divsd(xmm3, xmm1);
2246 __ movsd(xmm1, xmm3);
2247 __ jmp(&allocate_return);
2248
2249 // Test for 0.5.
2250 __ bind(&not_minus_half);
2251 // Load xmm2 with 0.5.
2252 // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
2253 __ addsd(xmm2, xmm3);
2254 // xmm2 now has 0.5.
2255 __ ucomisd(xmm2, xmm1);
2256 __ j(not_equal, &call_runtime);
2257 // Calculates square root.
2258 // sqrtsd returns -0 when input is -0. ECMA spec requires +0.
2259 __ xorpd(xmm1, xmm1);
2260 __ addsd(xmm1, xmm0);
2261 __ sqrtsd(xmm1, xmm1);
2262
2263 __ bind(&allocate_return);
2264 __ AllocateHeapNumber(rcx, rax, &call_runtime);
2265 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm1);
2266 __ movq(rax, rcx);
2267 __ ret(2 * kPointerSize);
2268
2269 __ bind(&call_runtime);
2270 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
2271 }
2272
2273
2073 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 2274 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
2074 // The key is in rdx and the parameter count is in rax. 2275 // The key is in rdx and the parameter count is in rax.
2075 2276
2076 // The displacement is used for skipping the frame pointer on the 2277 // The displacement is used for skipping the frame pointer on the
2077 // stack. It is the offset of the last parameter (if any) relative 2278 // stack. It is the offset of the last parameter (if any) relative
2078 // to the frame pointer. 2279 // to the frame pointer.
2079 static const int kDisplacement = 1 * kPointerSize; 2280 static const int kDisplacement = 1 * kPointerSize;
2080 2281
2081 // Check that the key is a smi. 2282 // Check that the key is a smi.
2082 Label slow; 2283 Label slow;
2083 __ JumpIfNotSmi(rdx, &slow); 2284 __ JumpIfNotSmi(rdx, &slow);
2084 2285
2085 // Check if the calling frame is an arguments adaptor frame. 2286 // Check if the calling frame is an arguments adaptor frame. We look at the
2287 // context offset, and if the frame is not a regular one, then we find a
2288 // Smi instead of the context. We can't use SmiCompare here, because that
2289 // only works for comparing two smis.
2086 Label adaptor; 2290 Label adaptor;
2087 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 2291 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2088 __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset), 2292 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
2089 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 2293 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2090 __ j(equal, &adaptor); 2294 __ j(equal, &adaptor);
2091 2295
2092 // Check index against formal parameters count limit passed in 2296 // Check index against formal parameters count limit passed in
2093 // through register rax. Use unsigned comparison to get negative 2297 // through register rax. Use unsigned comparison to get negative
2094 // check for free. 2298 // check for free.
2095 __ cmpq(rdx, rax); 2299 __ cmpq(rdx, rax);
2096 __ j(above_equal, &slow); 2300 __ j(above_equal, &slow);
2097 2301
2098 // Read the argument from the stack and return it. 2302 // Read the argument from the stack and return it.
2099 SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); 2303 SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2134 // rsp[24] : function 2338 // rsp[24] : function
2135 2339
2136 // The displacement is used for skipping the return address and the 2340 // The displacement is used for skipping the return address and the
2137 // frame pointer on the stack. It is the offset of the last 2341 // frame pointer on the stack. It is the offset of the last
2138 // parameter (if any) relative to the frame pointer. 2342 // parameter (if any) relative to the frame pointer.
2139 static const int kDisplacement = 2 * kPointerSize; 2343 static const int kDisplacement = 2 * kPointerSize;
2140 2344
2141 // Check if the calling frame is an arguments adaptor frame. 2345 // Check if the calling frame is an arguments adaptor frame.
2142 Label adaptor_frame, try_allocate, runtime; 2346 Label adaptor_frame, try_allocate, runtime;
2143 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 2347 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2144 __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), 2348 __ Cmp(Operand(rdx, StandardFrameConstants::kContextOffset),
2145 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 2349 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2146 __ j(equal, &adaptor_frame); 2350 __ j(equal, &adaptor_frame);
2147 2351
2148 // Get the length from the frame. 2352 // Get the length from the frame.
2149 __ SmiToInteger32(rcx, Operand(rsp, 1 * kPointerSize)); 2353 __ SmiToInteger32(rcx, Operand(rsp, 1 * kPointerSize));
2150 __ jmp(&try_allocate); 2354 __ jmp(&try_allocate);
2151 2355
2152 // Patch the arguments.length and the parameters pointer. 2356 // Patch the arguments.length and the parameters pointer.
2153 __ bind(&adaptor_frame); 2357 __ bind(&adaptor_frame);
2154 __ SmiToInteger32(rcx, 2358 __ SmiToInteger32(rcx,
2155 Operand(rdx, 2359 Operand(rdx,
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
2254 // rsp[16]: previous index 2458 // rsp[16]: previous index
2255 // rsp[24]: subject string 2459 // rsp[24]: subject string
2256 // rsp[32]: JSRegExp object 2460 // rsp[32]: JSRegExp object
2257 2461
2258 static const int kLastMatchInfoOffset = 1 * kPointerSize; 2462 static const int kLastMatchInfoOffset = 1 * kPointerSize;
2259 static const int kPreviousIndexOffset = 2 * kPointerSize; 2463 static const int kPreviousIndexOffset = 2 * kPointerSize;
2260 static const int kSubjectOffset = 3 * kPointerSize; 2464 static const int kSubjectOffset = 3 * kPointerSize;
2261 static const int kJSRegExpOffset = 4 * kPointerSize; 2465 static const int kJSRegExpOffset = 4 * kPointerSize;
2262 2466
2263 Label runtime; 2467 Label runtime;
2264
2265 // Ensure that a RegExp stack is allocated. 2468 // Ensure that a RegExp stack is allocated.
2266 ExternalReference address_of_regexp_stack_memory_address = 2469 ExternalReference address_of_regexp_stack_memory_address =
2267 ExternalReference::address_of_regexp_stack_memory_address(); 2470 ExternalReference::address_of_regexp_stack_memory_address();
2268 ExternalReference address_of_regexp_stack_memory_size = 2471 ExternalReference address_of_regexp_stack_memory_size =
2269 ExternalReference::address_of_regexp_stack_memory_size(); 2472 ExternalReference::address_of_regexp_stack_memory_size();
2270 __ movq(kScratchRegister, address_of_regexp_stack_memory_size); 2473 __ movq(kScratchRegister, address_of_regexp_stack_memory_size);
2271 __ movq(kScratchRegister, Operand(kScratchRegister, 0)); 2474 __ movq(kScratchRegister, Operand(kScratchRegister, 0));
2272 __ testq(kScratchRegister, kScratchRegister); 2475 __ testq(kScratchRegister, kScratchRegister);
2273 __ j(zero, &runtime); 2476 __ j(zero, &runtime);
2274 2477
2275 2478
2276 // Check that the first argument is a JSRegExp object. 2479 // Check that the first argument is a JSRegExp object.
2277 __ movq(rax, Operand(rsp, kJSRegExpOffset)); 2480 __ movq(rax, Operand(rsp, kJSRegExpOffset));
2278 __ JumpIfSmi(rax, &runtime); 2481 __ JumpIfSmi(rax, &runtime);
2279 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); 2482 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister);
2280 __ j(not_equal, &runtime); 2483 __ j(not_equal, &runtime);
2281 // Check that the RegExp has been compiled (data contains a fixed array). 2484 // Check that the RegExp has been compiled (data contains a fixed array).
2282 __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); 2485 __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset));
2283 if (FLAG_debug_code) { 2486 if (FLAG_debug_code) {
2284 Condition is_smi = masm->CheckSmi(rcx); 2487 Condition is_smi = masm->CheckSmi(rax);
2285 __ Check(NegateCondition(is_smi), 2488 __ Check(NegateCondition(is_smi),
2286 "Unexpected type for RegExp data, FixedArray expected"); 2489 "Unexpected type for RegExp data, FixedArray expected");
2287 __ CmpObjectType(rcx, FIXED_ARRAY_TYPE, kScratchRegister); 2490 __ CmpObjectType(rax, FIXED_ARRAY_TYPE, kScratchRegister);
2288 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); 2491 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected");
2289 } 2492 }
2290 2493
2291 // rcx: RegExp data (FixedArray) 2494 // rax: RegExp data (FixedArray)
2292 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. 2495 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
2293 __ SmiToInteger32(rbx, FieldOperand(rcx, JSRegExp::kDataTagOffset)); 2496 __ SmiToInteger32(rbx, FieldOperand(rax, JSRegExp::kDataTagOffset));
2294 __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP)); 2497 __ cmpl(rbx, Immediate(JSRegExp::IRREGEXP));
2295 __ j(not_equal, &runtime); 2498 __ j(not_equal, &runtime);
2296 2499
2297 // rcx: RegExp data (FixedArray) 2500 // rax: RegExp data (FixedArray)
2298 // Check that the number of captures fit in the static offsets vector buffer. 2501 // Check that the number of captures fit in the static offsets vector buffer.
2299 __ SmiToInteger32(rdx, 2502 __ SmiToInteger32(rdx,
2300 FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); 2503 FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset));
2301 // Calculate number of capture registers (number_of_captures + 1) * 2. 2504 // Calculate number of capture registers (number_of_captures + 1) * 2.
2302 __ leal(rdx, Operand(rdx, rdx, times_1, 2)); 2505 __ leal(rdx, Operand(rdx, rdx, times_1, 2));
2303 // Check that the static offsets vector buffer is large enough. 2506 // Check that the static offsets vector buffer is large enough.
2304 __ cmpl(rdx, Immediate(OffsetsVector::kStaticOffsetsVectorSize)); 2507 __ cmpl(rdx, Immediate(OffsetsVector::kStaticOffsetsVectorSize));
2305 __ j(above, &runtime); 2508 __ j(above, &runtime);
2306 2509
2307 // rcx: RegExp data (FixedArray) 2510 // rax: RegExp data (FixedArray)
2308 // rdx: Number of capture registers 2511 // rdx: Number of capture registers
2309 // Check that the second argument is a string. 2512 // Check that the second argument is a string.
2310 __ movq(rdi, Operand(rsp, kSubjectOffset)); 2513 __ movq(rdi, Operand(rsp, kSubjectOffset));
2311 __ JumpIfSmi(rdi, &runtime); 2514 __ JumpIfSmi(rdi, &runtime);
2312 Condition is_string = masm->IsObjectStringType(rdi, rbx, rbx); 2515 Condition is_string = masm->IsObjectStringType(rdi, rbx, rbx);
2313 __ j(NegateCondition(is_string), &runtime); 2516 __ j(NegateCondition(is_string), &runtime);
2314 2517
2315 // rdi: Subject string. 2518 // rdi: Subject string.
2316 // rax: RegExp data (FixedArray). 2519 // rax: RegExp data (FixedArray).
2317 // rdx: Number of capture registers. 2520 // rdx: Number of capture registers.
2318 // Check that the third argument is a positive smi less than the string 2521 // Check that the third argument is a positive smi less than the string
2319 // length. A negative value will be greater (unsigned comparison). 2522 // length. A negative value will be greater (unsigned comparison).
2320 __ movq(rbx, Operand(rsp, kPreviousIndexOffset)); 2523 __ movq(rbx, Operand(rsp, kPreviousIndexOffset));
2321 __ JumpIfNotSmi(rbx, &runtime); 2524 __ JumpIfNotSmi(rbx, &runtime);
2322 __ SmiCompare(rbx, FieldOperand(rdi, String::kLengthOffset)); 2525 __ SmiCompare(rbx, FieldOperand(rdi, String::kLengthOffset));
2323 __ j(above_equal, &runtime); 2526 __ j(above_equal, &runtime);
2324 2527
2325 // rax: RegExp data (FixedArray) 2528 // rax: RegExp data (FixedArray)
2326 // rdx: Number of capture registers 2529 // rdx: Number of capture registers
2327 // Check that the fourth object is a JSArray object. 2530 // Check that the fourth object is a JSArray object.
2328 __ movq(rdi, Operand(rsp, kLastMatchInfoOffset)); 2531 __ movq(rdi, Operand(rsp, kLastMatchInfoOffset));
2329 __ JumpIfSmi(rdi, &runtime); 2532 __ JumpIfSmi(rdi, &runtime);
2330 __ CmpObjectType(rdi, JS_ARRAY_TYPE, kScratchRegister); 2533 __ CmpObjectType(rdi, JS_ARRAY_TYPE, kScratchRegister);
2331 __ j(not_equal, &runtime); 2534 __ j(not_equal, &runtime);
2332 // Check that the JSArray is in fast case. 2535 // Check that the JSArray is in fast case.
2333 __ movq(rbx, FieldOperand(rdi, JSArray::kElementsOffset)); 2536 __ movq(rbx, FieldOperand(rdi, JSArray::kElementsOffset));
2334 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset)); 2537 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
2335 __ Cmp(rdi, Factory::fixed_array_map()); 2538 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
2539 Heap::kFixedArrayMapRootIndex);
2336 __ j(not_equal, &runtime); 2540 __ j(not_equal, &runtime);
2337 // Check that the last match info has space for the capture registers and the 2541 // Check that the last match info has space for the capture registers and the
2338 // additional information. Ensure no overflow in add. 2542 // additional information. Ensure no overflow in add.
2339 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); 2543 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset);
2340 __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset)); 2544 __ SmiToInteger32(rdi, FieldOperand(rbx, FixedArray::kLengthOffset));
2341 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead)); 2545 __ addl(rdx, Immediate(RegExpImpl::kLastMatchOverhead));
2342 __ cmpl(rdx, rdi); 2546 __ cmpl(rdx, rdi);
2343 __ j(greater, &runtime); 2547 __ j(greater, &runtime);
2344 2548
2345 // rax: RegExp data (FixedArray) 2549 // rax: RegExp data (FixedArray)
(...skipping 14 matching lines...) Expand all
2360 // Check for flat cons string. 2564 // Check for flat cons string.
2361 // A flat cons string is a cons string where the second part is the empty 2565 // A flat cons string is a cons string where the second part is the empty
2362 // string. In that case the subject string is just the first part of the cons 2566 // string. In that case the subject string is just the first part of the cons
2363 // string. Also in this case the first part of the cons string is known to be 2567 // string. Also in this case the first part of the cons string is known to be
2364 // a sequential string or an external string. 2568 // a sequential string or an external string.
2365 STATIC_ASSERT(kExternalStringTag !=0); 2569 STATIC_ASSERT(kExternalStringTag !=0);
2366 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); 2570 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0);
2367 __ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag)); 2571 __ testb(rbx, Immediate(kIsNotStringMask | kExternalStringTag));
2368 __ j(not_zero, &runtime); 2572 __ j(not_zero, &runtime);
2369 // String is a cons string. 2573 // String is a cons string.
2370 __ movq(rdx, FieldOperand(rdi, ConsString::kSecondOffset)); 2574 __ CompareRoot(FieldOperand(rdi, ConsString::kSecondOffset),
2371 __ Cmp(rdx, Factory::empty_string()); 2575 Heap::kEmptyStringRootIndex);
2372 __ j(not_equal, &runtime); 2576 __ j(not_equal, &runtime);
2373 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset)); 2577 __ movq(rdi, FieldOperand(rdi, ConsString::kFirstOffset));
2374 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); 2578 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset));
2375 // String is a cons string with empty second part. 2579 // String is a cons string with empty second part.
2376 // rdi: first part of cons string. 2580 // rdi: first part of cons string.
2377 // rbx: map of first part of cons string. 2581 // rbx: map of first part of cons string.
2378 // Is first part a flat two byte string? 2582 // Is first part a flat two byte string?
2379 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), 2583 __ testb(FieldOperand(rbx, Map::kInstanceTypeOffset),
2380 Immediate(kStringRepresentationMask | kStringEncodingMask)); 2584 Immediate(kStringRepresentationMask | kStringEncodingMask));
2381 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); 2585 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2415 // rdi: subject string 2619 // rdi: subject string
2416 // rbx: previous index 2620 // rbx: previous index
2417 // rcx: encoding of subject string (1 if ascii 0 if two_byte); 2621 // rcx: encoding of subject string (1 if ascii 0 if two_byte);
2418 // r11: code 2622 // r11: code
2419 // All checks done. Now push arguments for native regexp code. 2623 // All checks done. Now push arguments for native regexp code.
2420 __ IncrementCounter(&Counters::regexp_entry_native, 1); 2624 __ IncrementCounter(&Counters::regexp_entry_native, 1);
2421 2625
2422 static const int kRegExpExecuteArguments = 7; 2626 static const int kRegExpExecuteArguments = 7;
2423 int argument_slots_on_stack = 2627 int argument_slots_on_stack =
2424 masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments); 2628 masm->ArgumentStackSlotsForCFunctionCall(kRegExpExecuteArguments);
2425 __ EnterApiExitFrame(argument_slots_on_stack); // Clobbers rax! 2629 __ EnterApiExitFrame(argument_slots_on_stack);
2426 2630
2427 // Argument 7: Indicate that this is a direct call from JavaScript. 2631 // Argument 7: Indicate that this is a direct call from JavaScript.
2428 __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize), 2632 __ movq(Operand(rsp, (argument_slots_on_stack - 1) * kPointerSize),
2429 Immediate(1)); 2633 Immediate(1));
2430 2634
2431 // Argument 6: Start (high end) of backtracking stack memory area. 2635 // Argument 6: Start (high end) of backtracking stack memory area.
2432 __ movq(kScratchRegister, address_of_regexp_stack_memory_address); 2636 __ movq(kScratchRegister, address_of_regexp_stack_memory_address);
2433 __ movq(r9, Operand(kScratchRegister, 0)); 2637 __ movq(r9, Operand(kScratchRegister, 0));
2434 __ movq(kScratchRegister, address_of_regexp_stack_memory_size); 2638 __ movq(kScratchRegister, address_of_regexp_stack_memory_size);
2435 __ addq(r9, Operand(kScratchRegister, 0)); 2639 __ addq(r9, Operand(kScratchRegister, 0));
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2476 __ bind(&setup_two_byte); 2680 __ bind(&setup_two_byte);
2477 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset)); 2681 __ SmiToInteger32(rcx, FieldOperand(rdi, String::kLengthOffset));
2478 __ lea(arg4, FieldOperand(rdi, rcx, times_2, SeqTwoByteString::kHeaderSize)); 2682 __ lea(arg4, FieldOperand(rdi, rcx, times_2, SeqTwoByteString::kHeaderSize));
2479 __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize)); 2683 __ lea(arg3, FieldOperand(rdi, rbx, times_2, SeqTwoByteString::kHeaderSize));
2480 2684
2481 __ bind(&setup_rest); 2685 __ bind(&setup_rest);
2482 // Argument 2: Previous index. 2686 // Argument 2: Previous index.
2483 __ movq(arg2, rbx); 2687 __ movq(arg2, rbx);
2484 2688
2485 // Argument 1: Subject string. 2689 // Argument 1: Subject string.
2486 #ifdef WIN64_ 2690 #ifdef _WIN64
2487 __ movq(arg1, rdi); 2691 __ movq(arg1, rdi);
2488 #else 2692 #else
2489 // Already there in AMD64 calling convention. 2693 // Already there in AMD64 calling convention.
2490 ASSERT(arg1.is(rdi)); 2694 ASSERT(arg1.is(rdi));
2491 #endif 2695 #endif
2492 2696
2493 // Locate the code entry and call it. 2697 // Locate the code entry and call it.
2494 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag)); 2698 __ addq(r11, Immediate(Code::kHeaderSize - kHeapObjectTag));
2495 __ call(r11); 2699 __ call(r11);
2496 2700
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
2629 // rbx: Number of array elements as int32. 2833 // rbx: Number of array elements as int32.
2630 // r8: Number of array elements as smi. 2834 // r8: Number of array elements as smi.
2631 2835
2632 // Set JSArray map to global.regexp_result_map(). 2836 // Set JSArray map to global.regexp_result_map().
2633 __ movq(rdx, ContextOperand(rsi, Context::GLOBAL_INDEX)); 2837 __ movq(rdx, ContextOperand(rsi, Context::GLOBAL_INDEX));
2634 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset)); 2838 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
2635 __ movq(rdx, ContextOperand(rdx, Context::REGEXP_RESULT_MAP_INDEX)); 2839 __ movq(rdx, ContextOperand(rdx, Context::REGEXP_RESULT_MAP_INDEX));
2636 __ movq(FieldOperand(rax, HeapObject::kMapOffset), rdx); 2840 __ movq(FieldOperand(rax, HeapObject::kMapOffset), rdx);
2637 2841
2638 // Set empty properties FixedArray. 2842 // Set empty properties FixedArray.
2639 __ Move(FieldOperand(rax, JSObject::kPropertiesOffset), 2843 __ LoadRoot(kScratchRegister, Heap::kEmptyFixedArrayRootIndex);
2640 Factory::empty_fixed_array()); 2844 __ movq(FieldOperand(rax, JSObject::kPropertiesOffset), kScratchRegister);
2641 2845
2642 // Set elements to point to FixedArray allocated right after the JSArray. 2846 // Set elements to point to FixedArray allocated right after the JSArray.
2643 __ lea(rcx, Operand(rax, JSRegExpResult::kSize)); 2847 __ lea(rcx, Operand(rax, JSRegExpResult::kSize));
2644 __ movq(FieldOperand(rax, JSObject::kElementsOffset), rcx); 2848 __ movq(FieldOperand(rax, JSObject::kElementsOffset), rcx);
2645 2849
2646 // Set input, index and length fields from arguments. 2850 // Set input, index and length fields from arguments.
2647 __ movq(r8, Operand(rsp, kPointerSize * 1)); 2851 __ movq(r8, Operand(rsp, kPointerSize * 1));
2648 __ movq(FieldOperand(rax, JSRegExpResult::kInputOffset), r8); 2852 __ movq(FieldOperand(rax, JSRegExpResult::kInputOffset), r8);
2649 __ movq(r8, Operand(rsp, kPointerSize * 2)); 2853 __ movq(r8, Operand(rsp, kPointerSize * 2));
2650 __ movq(FieldOperand(rax, JSRegExpResult::kIndexOffset), r8); 2854 __ movq(FieldOperand(rax, JSRegExpResult::kIndexOffset), r8);
2651 __ movq(r8, Operand(rsp, kPointerSize * 3)); 2855 __ movq(r8, Operand(rsp, kPointerSize * 3));
2652 __ movq(FieldOperand(rax, JSArray::kLengthOffset), r8); 2856 __ movq(FieldOperand(rax, JSArray::kLengthOffset), r8);
2653 2857
2654 // Fill out the elements FixedArray. 2858 // Fill out the elements FixedArray.
2655 // rax: JSArray. 2859 // rax: JSArray.
2656 // rcx: FixedArray. 2860 // rcx: FixedArray.
2657 // rbx: Number of elements in array as int32. 2861 // rbx: Number of elements in array as int32.
2658 2862
2659 // Set map. 2863 // Set map.
2660 __ Move(FieldOperand(rcx, HeapObject::kMapOffset), 2864 __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex);
2661 Factory::fixed_array_map()); 2865 __ movq(FieldOperand(rcx, HeapObject::kMapOffset), kScratchRegister);
2662 // Set length. 2866 // Set length.
2663 __ Integer32ToSmi(rdx, rbx); 2867 __ Integer32ToSmi(rdx, rbx);
2664 __ movq(FieldOperand(rcx, FixedArray::kLengthOffset), rdx); 2868 __ movq(FieldOperand(rcx, FixedArray::kLengthOffset), rdx);
2665 // Fill contents of fixed-array with the-hole. 2869 // Fill contents of fixed-array with the-hole.
2666 __ Move(rdx, Factory::the_hole_value()); 2870 __ LoadRoot(rdx, Heap::kTheHoleValueRootIndex);
2667 __ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize)); 2871 __ lea(rcx, FieldOperand(rcx, FixedArray::kHeaderSize));
2668 // Fill fixed array elements with hole. 2872 // Fill fixed array elements with hole.
2669 // rax: JSArray. 2873 // rax: JSArray.
2670 // rbx: Number of elements in array that remains to be filled, as int32. 2874 // rbx: Number of elements in array that remains to be filled, as int32.
2671 // rcx: Start of elements in FixedArray. 2875 // rcx: Start of elements in FixedArray.
2672 // rdx: the hole. 2876 // rdx: the hole.
2673 Label loop; 2877 Label loop;
2674 __ testl(rbx, rbx); 2878 __ testl(rbx, rbx);
2675 __ bind(&loop); 2879 __ bind(&loop);
2676 __ j(less_equal, &done); // Jump if rcx is negative or zero. 2880 __ j(less_equal, &done); // Jump if rcx is negative or zero.
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after
3135 // of the original receiver from the call site). 3339 // of the original receiver from the call site).
3136 __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi); 3340 __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi);
3137 __ Set(rax, argc_); 3341 __ Set(rax, argc_);
3138 __ Set(rbx, 0); 3342 __ Set(rbx, 0);
3139 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); 3343 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
3140 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); 3344 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
3141 __ Jump(adaptor, RelocInfo::CODE_TARGET); 3345 __ Jump(adaptor, RelocInfo::CODE_TARGET);
3142 } 3346 }
3143 3347
3144 3348
3349 bool CEntryStub::NeedsImmovableCode() {
3350 return false;
3351 }
3352
3353
3145 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { 3354 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
3146 // Throw exception in eax. 3355 // Throw exception in eax.
3147 __ Throw(rax); 3356 __ Throw(rax);
3148 } 3357 }
3149 3358
3150 3359
3151 void CEntryStub::GenerateCore(MacroAssembler* masm, 3360 void CEntryStub::GenerateCore(MacroAssembler* masm,
3152 Label* throw_normal_exception, 3361 Label* throw_normal_exception,
3153 Label* throw_termination_exception, 3362 Label* throw_termination_exception,
3154 Label* throw_out_of_memory_exception, 3363 Label* throw_out_of_memory_exception,
3155 bool do_gc, 3364 bool do_gc,
3156 bool always_allocate_scope) { 3365 bool always_allocate_scope) {
3157 // rax: result parameter for PerformGC, if any. 3366 // rax: result parameter for PerformGC, if any.
3158 // rbx: pointer to C function (C callee-saved). 3367 // rbx: pointer to C function (C callee-saved).
3159 // rbp: frame pointer (restored after C call). 3368 // rbp: frame pointer (restored after C call).
3160 // rsp: stack pointer (restored after C call). 3369 // rsp: stack pointer (restored after C call).
3161 // r14: number of arguments including receiver (C callee-saved). 3370 // r14: number of arguments including receiver (C callee-saved).
3162 // r12: pointer to the first argument (C callee-saved). 3371 // r15: pointer to the first argument (C callee-saved).
3163 // This pointer is reused in LeaveExitFrame(), so it is stored in a 3372 // This pointer is reused in LeaveExitFrame(), so it is stored in a
3164 // callee-saved register. 3373 // callee-saved register.
3165 3374
3166 // Simple results returned in rax (both AMD64 and Win64 calling conventions). 3375 // Simple results returned in rax (both AMD64 and Win64 calling conventions).
3167 // Complex results must be written to address passed as first argument. 3376 // Complex results must be written to address passed as first argument.
3168 // AMD64 calling convention: a struct of two pointers in rax+rdx 3377 // AMD64 calling convention: a struct of two pointers in rax+rdx
3169 3378
3170 // Check stack alignment. 3379 // Check stack alignment.
3171 if (FLAG_debug_code) { 3380 if (FLAG_debug_code) {
3172 __ CheckStackAlignment(); 3381 __ CheckStackAlignment();
(...skipping 20 matching lines...) Expand all
3193 if (always_allocate_scope) { 3402 if (always_allocate_scope) {
3194 __ movq(kScratchRegister, scope_depth); 3403 __ movq(kScratchRegister, scope_depth);
3195 __ incl(Operand(kScratchRegister, 0)); 3404 __ incl(Operand(kScratchRegister, 0));
3196 } 3405 }
3197 3406
3198 // Call C function. 3407 // Call C function.
3199 #ifdef _WIN64 3408 #ifdef _WIN64
3200 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9 3409 // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9
3201 // Store Arguments object on stack, below the 4 WIN64 ABI parameter slots. 3410 // Store Arguments object on stack, below the 4 WIN64 ABI parameter slots.
3202 __ movq(StackSpaceOperand(0), r14); // argc. 3411 __ movq(StackSpaceOperand(0), r14); // argc.
3203 __ movq(StackSpaceOperand(1), r12); // argv. 3412 __ movq(StackSpaceOperand(1), r15); // argv.
3204 if (result_size_ < 2) { 3413 if (result_size_ < 2) {
3205 // Pass a pointer to the Arguments object as the first argument. 3414 // Pass a pointer to the Arguments object as the first argument.
3206 // Return result in single register (rax). 3415 // Return result in single register (rax).
3207 __ lea(rcx, StackSpaceOperand(0)); 3416 __ lea(rcx, StackSpaceOperand(0));
3208 } else { 3417 } else {
3209 ASSERT_EQ(2, result_size_); 3418 ASSERT_EQ(2, result_size_);
3210 // Pass a pointer to the result location as the first argument. 3419 // Pass a pointer to the result location as the first argument.
3211 __ lea(rcx, StackSpaceOperand(2)); 3420 __ lea(rcx, StackSpaceOperand(2));
3212 // Pass a pointer to the Arguments object as the second argument. 3421 // Pass a pointer to the Arguments object as the second argument.
3213 __ lea(rdx, StackSpaceOperand(0)); 3422 __ lea(rdx, StackSpaceOperand(0));
3214 } 3423 }
3215 3424
3216 #else // _WIN64 3425 #else // _WIN64
3217 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9. 3426 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9.
3218 __ movq(rdi, r14); // argc. 3427 __ movq(rdi, r14); // argc.
3219 __ movq(rsi, r12); // argv. 3428 __ movq(rsi, r15); // argv.
3220 #endif 3429 #endif
3221 __ call(rbx); 3430 __ call(rbx);
3222 // Result is in rax - do not destroy this register! 3431 // Result is in rax - do not destroy this register!
3223 3432
3224 if (always_allocate_scope) { 3433 if (always_allocate_scope) {
3225 __ movq(kScratchRegister, scope_depth); 3434 __ movq(kScratchRegister, scope_depth);
3226 __ decl(Operand(kScratchRegister, 0)); 3435 __ decl(Operand(kScratchRegister, 0));
3227 } 3436 }
3228 3437
3229 // Check for failure result. 3438 // Check for failure result.
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
3313 // rax: Holds the context at this point, but should not be used. 3522 // rax: Holds the context at this point, but should not be used.
3314 // On entry to code generated by GenerateCore, it must hold 3523 // On entry to code generated by GenerateCore, it must hold
3315 // a failure result if the collect_garbage argument to GenerateCore 3524 // a failure result if the collect_garbage argument to GenerateCore
3316 // is true. This failure result can be the result of code 3525 // is true. This failure result can be the result of code
3317 // generated by a previous call to GenerateCore. The value 3526 // generated by a previous call to GenerateCore. The value
3318 // of rax is then passed to Runtime::PerformGC. 3527 // of rax is then passed to Runtime::PerformGC.
3319 // rbx: pointer to builtin function (C callee-saved). 3528 // rbx: pointer to builtin function (C callee-saved).
3320 // rbp: frame pointer of exit frame (restored after C call). 3529 // rbp: frame pointer of exit frame (restored after C call).
3321 // rsp: stack pointer (restored after C call). 3530 // rsp: stack pointer (restored after C call).
3322 // r14: number of arguments including receiver (C callee-saved). 3531 // r14: number of arguments including receiver (C callee-saved).
3323 // r12: argv pointer (C callee-saved). 3532 // r15: argv pointer (C callee-saved).
3324 3533
3325 Label throw_normal_exception; 3534 Label throw_normal_exception;
3326 Label throw_termination_exception; 3535 Label throw_termination_exception;
3327 Label throw_out_of_memory_exception; 3536 Label throw_out_of_memory_exception;
3328 3537
3329 // Call into the runtime system. 3538 // Call into the runtime system.
3330 GenerateCore(masm, 3539 GenerateCore(masm,
3331 &throw_normal_exception, 3540 &throw_normal_exception,
3332 &throw_termination_exception, 3541 &throw_termination_exception,
3333 &throw_out_of_memory_exception, 3542 &throw_out_of_memory_exception,
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
3396 // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are 3605 // TODO(X64): On Win64, if we ever use XMM6-XMM15, the low low 64 bits are
3397 // callee save as well. 3606 // callee save as well.
3398 3607
3399 // Save copies of the top frame descriptor on the stack. 3608 // Save copies of the top frame descriptor on the stack.
3400 ExternalReference c_entry_fp(Top::k_c_entry_fp_address); 3609 ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
3401 __ load_rax(c_entry_fp); 3610 __ load_rax(c_entry_fp);
3402 __ push(rax); 3611 __ push(rax);
3403 3612
3404 // Set up the roots and smi constant registers. 3613 // Set up the roots and smi constant registers.
3405 // Needs to be done before any further smi loads. 3614 // Needs to be done before any further smi loads.
3406 ExternalReference roots_address = ExternalReference::roots_address(); 3615 __ InitializeRootRegister();
3407 __ movq(kRootRegister, roots_address);
3408 __ InitializeSmiConstantRegister(); 3616 __ InitializeSmiConstantRegister();
3409 3617
3410 #ifdef ENABLE_LOGGING_AND_PROFILING 3618 #ifdef ENABLE_LOGGING_AND_PROFILING
3411 // If this is the outermost JS call, set js_entry_sp value. 3619 // If this is the outermost JS call, set js_entry_sp value.
3412 ExternalReference js_entry_sp(Top::k_js_entry_sp_address); 3620 ExternalReference js_entry_sp(Top::k_js_entry_sp_address);
3413 __ load_rax(js_entry_sp); 3621 __ load_rax(js_entry_sp);
3414 __ testq(rax, rax); 3622 __ testq(rax, rax);
3415 __ j(not_zero, &not_outermost_js); 3623 __ j(not_zero, &not_outermost_js);
3416 __ movq(rax, rbp); 3624 __ movq(rax, rbp);
3417 __ store_rax(js_entry_sp); 3625 __ store_rax(js_entry_sp);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
3489 __ addq(rsp, Immediate(2 * kPointerSize)); // remove markers 3697 __ addq(rsp, Immediate(2 * kPointerSize)); // remove markers
3490 3698
3491 // Restore frame pointer and return. 3699 // Restore frame pointer and return.
3492 __ pop(rbp); 3700 __ pop(rbp);
3493 __ ret(0); 3701 __ ret(0);
3494 } 3702 }
3495 3703
3496 3704
3497 void InstanceofStub::Generate(MacroAssembler* masm) { 3705 void InstanceofStub::Generate(MacroAssembler* masm) {
3498 // Implements "value instanceof function" operator. 3706 // Implements "value instanceof function" operator.
3499 // Expected input state: 3707 // Expected input state with no inline cache:
3500 // rsp[0] : return address 3708 // rsp[0] : return address
3501 // rsp[1] : function pointer 3709 // rsp[1] : function pointer
3502 // rsp[2] : value 3710 // rsp[2] : value
3711 // Expected input state with an inline one-element cache:
3712 // rsp[0] : return address
3713 // rsp[1] : offset from return address to location of inline cache
3714 // rsp[2] : function pointer
3715 // rsp[3] : value
3503 // Returns a bitwise zero to indicate that the value 3716 // Returns a bitwise zero to indicate that the value
3504 // is and instance of the function and anything else to 3717 // is and instance of the function and anything else to
3505 // indicate that the value is not an instance. 3718 // indicate that the value is not an instance.
3506 3719
3720 static const int kOffsetToMapCheckValue = 5;
3721 static const int kOffsetToResultValue = 21;
3722 // The last 4 bytes of the instruction sequence
3723 // movq(rax, FieldOperand(rdi, HeapObject::kMapOffset)
3724 // Move(kScratchRegister, Factory::the_hole_value)
3725 // in front of the hole value address.
3726 static const unsigned int kWordBeforeMapCheckValue = 0xBA49FF78;
3727 // The last 4 bytes of the instruction sequence
3728 // __ j(not_equal, &cache_miss);
3729 // __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
3730 // before the offset of the hole value in the root array.
3731 static const unsigned int kWordBeforeResultValue = 0x458B4909;
3732 // Only the inline check flag is supported on X64.
3733 ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck());
3734 int extra_stack_space = HasCallSiteInlineCheck() ? kPointerSize : 0;
3735
3507 // Get the object - go slow case if it's a smi. 3736 // Get the object - go slow case if it's a smi.
3508 Label slow; 3737 Label slow;
3509 __ movq(rax, Operand(rsp, 2 * kPointerSize)); 3738
3739 __ movq(rax, Operand(rsp, 2 * kPointerSize + extra_stack_space));
3510 __ JumpIfSmi(rax, &slow); 3740 __ JumpIfSmi(rax, &slow);
3511 3741
3512 // Check that the left hand is a JS object. Leave its map in rax. 3742 // Check that the left hand is a JS object. Leave its map in rax.
3513 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax); 3743 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax);
3514 __ j(below, &slow); 3744 __ j(below, &slow);
3515 __ CmpInstanceType(rax, LAST_JS_OBJECT_TYPE); 3745 __ CmpInstanceType(rax, LAST_JS_OBJECT_TYPE);
3516 __ j(above, &slow); 3746 __ j(above, &slow);
3517 3747
3518 // Get the prototype of the function. 3748 // Get the prototype of the function.
3519 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); 3749 __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space));
3520 // rdx is function, rax is map. 3750 // rdx is function, rax is map.
3521 3751
3522 // Look up the function and the map in the instanceof cache. 3752 // If there is a call site cache don't look in the global cache, but do the
3523 NearLabel miss; 3753 // real lookup and update the call site cache.
3524 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); 3754 if (!HasCallSiteInlineCheck()) {
3525 __ j(not_equal, &miss); 3755 // Look up the function and the map in the instanceof cache.
3526 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); 3756 NearLabel miss;
3527 __ j(not_equal, &miss); 3757 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
3528 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); 3758 __ j(not_equal, &miss);
3529 __ ret(2 * kPointerSize); 3759 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex);
3760 __ j(not_equal, &miss);
3761 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
3762 __ ret(2 * kPointerSize);
3763 __ bind(&miss);
3764 }
3530 3765
3531 __ bind(&miss);
3532 __ TryGetFunctionPrototype(rdx, rbx, &slow); 3766 __ TryGetFunctionPrototype(rdx, rbx, &slow);
3533 3767
3534 // Check that the function prototype is a JS object. 3768 // Check that the function prototype is a JS object.
3535 __ JumpIfSmi(rbx, &slow); 3769 __ JumpIfSmi(rbx, &slow);
3536 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); 3770 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister);
3537 __ j(below, &slow); 3771 __ j(below, &slow);
3538 __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); 3772 __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE);
3539 __ j(above, &slow); 3773 __ j(above, &slow);
3540 3774
3541 // Register mapping: 3775 // Register mapping:
3542 // rax is object map. 3776 // rax is object map.
3543 // rdx is function. 3777 // rdx is function.
3544 // rbx is function prototype. 3778 // rbx is function prototype.
3545 __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); 3779 if (!HasCallSiteInlineCheck()) {
3546 __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); 3780 __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex);
3781 __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex);
3782 } else {
3783 __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
3784 __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
3785 __ movq(Operand(kScratchRegister, kOffsetToMapCheckValue), rax);
3786 if (FLAG_debug_code) {
3787 __ movl(rdi, Immediate(kWordBeforeMapCheckValue));
3788 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi);
3789 __ Assert(equal, "InstanceofStub unexpected call site cache.");
3790 }
3791 }
3547 3792
3548 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); 3793 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset));
3549 3794
3550 // Loop through the prototype chain looking for the function prototype. 3795 // Loop through the prototype chain looking for the function prototype.
3551 NearLabel loop, is_instance, is_not_instance; 3796 NearLabel loop, is_instance, is_not_instance;
3552 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); 3797 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex);
3553 __ bind(&loop); 3798 __ bind(&loop);
3554 __ cmpq(rcx, rbx); 3799 __ cmpq(rcx, rbx);
3555 __ j(equal, &is_instance); 3800 __ j(equal, &is_instance);
3556 __ cmpq(rcx, kScratchRegister); 3801 __ cmpq(rcx, kScratchRegister);
3557 // The code at is_not_instance assumes that kScratchRegister contains a 3802 // The code at is_not_instance assumes that kScratchRegister contains a
3558 // non-zero GCable value (the null object in this case). 3803 // non-zero GCable value (the null object in this case).
3559 __ j(equal, &is_not_instance); 3804 __ j(equal, &is_not_instance);
3560 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); 3805 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
3561 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); 3806 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset));
3562 __ jmp(&loop); 3807 __ jmp(&loop);
3563 3808
3564 __ bind(&is_instance); 3809 __ bind(&is_instance);
3565 __ xorl(rax, rax); 3810 if (!HasCallSiteInlineCheck()) {
3566 // Store bitwise zero in the cache. This is a Smi in GC terms. 3811 __ xorl(rax, rax);
3567 STATIC_ASSERT(kSmiTag == 0); 3812 // Store bitwise zero in the cache. This is a Smi in GC terms.
3568 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); 3813 STATIC_ASSERT(kSmiTag == 0);
3569 __ ret(2 * kPointerSize); 3814 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex);
3815 } else {
3816 // Store offset of true in the root array at the inline check site.
3817 ASSERT((Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias
3818 == 0xB0 - 0x100);
3819 __ movl(rax, Immediate(0xB0)); // TrueValue is at -10 * kPointerSize.
3820 __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
3821 __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
3822 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
3823 if (FLAG_debug_code) {
3824 __ movl(rax, Immediate(kWordBeforeResultValue));
3825 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax);
3826 __ Assert(equal, "InstanceofStub unexpected call site cache.");
3827 }
3828 __ xorl(rax, rax);
3829 }
3830 __ ret(2 * kPointerSize + extra_stack_space);
3570 3831
3571 __ bind(&is_not_instance); 3832 __ bind(&is_not_instance);
3572 // We have to store a non-zero value in the cache. 3833 if (!HasCallSiteInlineCheck()) {
3573 __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); 3834 // We have to store a non-zero value in the cache.
3574 __ ret(2 * kPointerSize); 3835 __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex);
3836 } else {
3837 // Store offset of false in the root array at the inline check site.
3838 ASSERT((Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias
3839 == 0xB8 - 0x100);
3840 __ movl(rax, Immediate(0xB8)); // FalseValue is at -9 * kPointerSize.
3841 __ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
3842 __ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
3843 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
3844 if (FLAG_debug_code) {
3845 __ movl(rax, Immediate(kWordBeforeResultValue));
3846 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax);
3847 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)");
3848 }
3849 }
3850 __ ret(2 * kPointerSize + extra_stack_space);
3575 3851
3576 // Slow-case: Go through the JavaScript implementation. 3852 // Slow-case: Go through the JavaScript implementation.
3577 __ bind(&slow); 3853 __ bind(&slow);
3854 if (HasCallSiteInlineCheck()) {
3855 // Remove extra value from the stack.
3856 __ pop(rcx);
3857 __ pop(rax);
3858 __ push(rcx);
3859 }
3578 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 3860 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
3579 } 3861 }
3580 3862
3581 3863
3582 Register InstanceofStub::left() { return rax; } 3864 // Passing arguments in registers is not supported.
3865 Register InstanceofStub::left() { return no_reg; }
3583 3866
3584 3867
3585 Register InstanceofStub::right() { return rdx; } 3868 Register InstanceofStub::right() { return no_reg; }
3586 3869
3587 3870
3588 int CompareStub::MinorKey() { 3871 int CompareStub::MinorKey() {
3589 // Encode the three parameters in a unique 16 bit value. To avoid duplicate 3872 // Encode the three parameters in a unique 16 bit value. To avoid duplicate
3590 // stubs the never NaN NaN condition is only taken into account if the 3873 // stubs the never NaN NaN condition is only taken into account if the
3591 // condition is equals. 3874 // condition is equals.
3592 ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); 3875 ASSERT(static_cast<unsigned>(cc_) < (1 << 12));
3593 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 3876 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg));
3594 return ConditionField::encode(static_cast<unsigned>(cc_)) 3877 return ConditionField::encode(static_cast<unsigned>(cc_))
3595 | RegisterField::encode(false) // lhs_ and rhs_ are not used 3878 | RegisterField::encode(false) // lhs_ and rhs_ are not used
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
3834 4117
3835 4118
3836 void StringCharAtGenerator::GenerateSlow( 4119 void StringCharAtGenerator::GenerateSlow(
3837 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { 4120 MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
3838 char_code_at_generator_.GenerateSlow(masm, call_helper); 4121 char_code_at_generator_.GenerateSlow(masm, call_helper);
3839 char_from_code_generator_.GenerateSlow(masm, call_helper); 4122 char_from_code_generator_.GenerateSlow(masm, call_helper);
3840 } 4123 }
3841 4124
3842 4125
3843 void StringAddStub::Generate(MacroAssembler* masm) { 4126 void StringAddStub::Generate(MacroAssembler* masm) {
3844 Label string_add_runtime; 4127 Label string_add_runtime, call_builtin;
4128 Builtins::JavaScript builtin_id = Builtins::ADD;
3845 4129
3846 // Load the two arguments. 4130 // Load the two arguments.
3847 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument. 4131 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left).
3848 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument. 4132 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right).
3849 4133
3850 // Make sure that both arguments are strings if not known in advance. 4134 // Make sure that both arguments are strings if not known in advance.
3851 if (string_check_) { 4135 if (flags_ == NO_STRING_ADD_FLAGS) {
3852 Condition is_smi; 4136 Condition is_smi;
3853 is_smi = masm->CheckSmi(rax); 4137 is_smi = masm->CheckSmi(rax);
3854 __ j(is_smi, &string_add_runtime); 4138 __ j(is_smi, &string_add_runtime);
3855 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); 4139 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8);
3856 __ j(above_equal, &string_add_runtime); 4140 __ j(above_equal, &string_add_runtime);
3857 4141
3858 // First argument is a a string, test second. 4142 // First argument is a a string, test second.
3859 is_smi = masm->CheckSmi(rdx); 4143 is_smi = masm->CheckSmi(rdx);
3860 __ j(is_smi, &string_add_runtime); 4144 __ j(is_smi, &string_add_runtime);
3861 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); 4145 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9);
3862 __ j(above_equal, &string_add_runtime); 4146 __ j(above_equal, &string_add_runtime);
4147 } else {
4148 // Here at least one of the arguments is definitely a string.
4149 // We convert the one that is not known to be a string.
4150 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) {
4151 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0);
4152 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi,
4153 &call_builtin);
4154 builtin_id = Builtins::STRING_ADD_RIGHT;
4155 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) {
4156 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0);
4157 GenerateConvertArgument(masm, 1 * kPointerSize, rdx, rbx, rcx, rdi,
4158 &call_builtin);
4159 builtin_id = Builtins::STRING_ADD_LEFT;
4160 }
3863 } 4161 }
3864 4162
3865 // Both arguments are strings. 4163 // Both arguments are strings.
3866 // rax: first string 4164 // rax: first string
3867 // rdx: second string 4165 // rdx: second string
3868 // Check if either of the strings are empty. In that case return the other. 4166 // Check if either of the strings are empty. In that case return the other.
3869 NearLabel second_not_zero_length, both_not_zero_length; 4167 NearLabel second_not_zero_length, both_not_zero_length;
3870 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset)); 4168 __ movq(rcx, FieldOperand(rdx, String::kLengthOffset));
3871 __ SmiTest(rcx); 4169 __ SmiTest(rcx);
3872 __ j(not_zero, &second_not_zero_length); 4170 __ j(not_zero, &second_not_zero_length);
3873 // Second string is empty, result is first string which is already in rax. 4171 // Second string is empty, result is first string which is already in rax.
3874 __ IncrementCounter(&Counters::string_add_native, 1); 4172 __ IncrementCounter(&Counters::string_add_native, 1);
3875 __ ret(2 * kPointerSize); 4173 __ ret(2 * kPointerSize);
3876 __ bind(&second_not_zero_length); 4174 __ bind(&second_not_zero_length);
3877 __ movq(rbx, FieldOperand(rax, String::kLengthOffset)); 4175 __ movq(rbx, FieldOperand(rax, String::kLengthOffset));
3878 __ SmiTest(rbx); 4176 __ SmiTest(rbx);
3879 __ j(not_zero, &both_not_zero_length); 4177 __ j(not_zero, &both_not_zero_length);
3880 // First string is empty, result is second string which is in rdx. 4178 // First string is empty, result is second string which is in rdx.
3881 __ movq(rax, rdx); 4179 __ movq(rax, rdx);
3882 __ IncrementCounter(&Counters::string_add_native, 1); 4180 __ IncrementCounter(&Counters::string_add_native, 1);
3883 __ ret(2 * kPointerSize); 4181 __ ret(2 * kPointerSize);
3884 4182
3885 // Both strings are non-empty. 4183 // Both strings are non-empty.
3886 // rax: first string 4184 // rax: first string
3887 // rbx: length of first string 4185 // rbx: length of first string
3888 // rcx: length of second string 4186 // rcx: length of second string
3889 // rdx: second string 4187 // rdx: second string
3890 // r8: map of first string if string check was performed above 4188 // r8: map of first string (if flags_ == NO_STRING_ADD_FLAGS)
3891 // r9: map of second string if string check was performed above 4189 // r9: map of second string (if flags_ == NO_STRING_ADD_FLAGS)
3892 Label string_add_flat_result, longer_than_two; 4190 Label string_add_flat_result, longer_than_two;
3893 __ bind(&both_not_zero_length); 4191 __ bind(&both_not_zero_length);
3894 4192
3895 // If arguments where known to be strings, maps are not loaded to r8 and r9 4193 // If arguments where known to be strings, maps are not loaded to r8 and r9
3896 // by the code above. 4194 // by the code above.
3897 if (!string_check_) { 4195 if (flags_ != NO_STRING_ADD_FLAGS) {
3898 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); 4196 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset));
3899 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); 4197 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
3900 } 4198 }
3901 // Get the instance types of the two strings as they will be needed soon. 4199 // Get the instance types of the two strings as they will be needed soon.
3902 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); 4200 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset));
3903 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); 4201 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset));
3904 4202
3905 // Look at the length of the result of adding the two strings. 4203 // Look at the length of the result of adding the two strings.
3906 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); 4204 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2);
3907 __ SmiAdd(rbx, rbx, rcx); 4205 __ SmiAdd(rbx, rbx, rcx);
3908 // Use the runtime system when adding two one character strings, as it 4206 // Use the symbol table when adding two one character strings, as it
3909 // contains optimizations for this specific case using the symbol table. 4207 // helps later optimizations to return a symbol here.
3910 __ SmiCompare(rbx, Smi::FromInt(2)); 4208 __ SmiCompare(rbx, Smi::FromInt(2));
3911 __ j(not_equal, &longer_than_two); 4209 __ j(not_equal, &longer_than_two);
3912 4210
3913 // Check that both strings are non-external ascii strings. 4211 // Check that both strings are non-external ascii strings.
3914 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, 4212 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx,
3915 &string_add_runtime); 4213 &string_add_runtime);
3916 4214
3917 // Get the two characters forming the sub string. 4215 // Get the two characters forming the sub string.
3918 __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); 4216 __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize));
3919 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); 4217 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize));
3920 4218
3921 // Try to lookup two character string in symbol table. If it is not found 4219 // Try to lookup two character string in symbol table. If it is not found
3922 // just allocate a new one. 4220 // just allocate a new one.
3923 Label make_two_character_string, make_flat_ascii_string; 4221 Label make_two_character_string, make_flat_ascii_string;
3924 StringHelper::GenerateTwoCharacterSymbolTableProbe( 4222 StringHelper::GenerateTwoCharacterSymbolTableProbe(
3925 masm, rbx, rcx, r14, r11, rdi, r12, &make_two_character_string); 4223 masm, rbx, rcx, r14, r11, rdi, r15, &make_two_character_string);
3926 __ IncrementCounter(&Counters::string_add_native, 1); 4224 __ IncrementCounter(&Counters::string_add_native, 1);
3927 __ ret(2 * kPointerSize); 4225 __ ret(2 * kPointerSize);
3928 4226
3929 __ bind(&make_two_character_string); 4227 __ bind(&make_two_character_string);
3930 __ Set(rbx, 2); 4228 __ Set(rbx, 2);
3931 __ jmp(&make_flat_ascii_string); 4229 __ jmp(&make_flat_ascii_string);
3932 4230
3933 __ bind(&longer_than_two); 4231 __ bind(&longer_than_two);
3934 // Check if resulting string will be flat. 4232 // Check if resulting string will be flat.
3935 __ SmiCompare(rbx, Smi::FromInt(String::kMinNonFlatLength)); 4233 __ SmiCompare(rbx, Smi::FromInt(String::kMinNonFlatLength));
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
4073 // rdx: first char of second argument 4371 // rdx: first char of second argument
4074 // rdi: length of second argument 4372 // rdi: length of second argument
4075 StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false); 4373 StringHelper::GenerateCopyCharacters(masm, rcx, rdx, rdi, false);
4076 __ movq(rax, rbx); 4374 __ movq(rax, rbx);
4077 __ IncrementCounter(&Counters::string_add_native, 1); 4375 __ IncrementCounter(&Counters::string_add_native, 1);
4078 __ ret(2 * kPointerSize); 4376 __ ret(2 * kPointerSize);
4079 4377
4080 // Just jump to runtime to add the two strings. 4378 // Just jump to runtime to add the two strings.
4081 __ bind(&string_add_runtime); 4379 __ bind(&string_add_runtime);
4082 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); 4380 __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
4381
4382 if (call_builtin.is_linked()) {
4383 __ bind(&call_builtin);
4384 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
4385 }
4386 }
4387
4388
4389 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
4390 int stack_offset,
4391 Register arg,
4392 Register scratch1,
4393 Register scratch2,
4394 Register scratch3,
4395 Label* slow) {
4396 // First check if the argument is already a string.
4397 Label not_string, done;
4398 __ JumpIfSmi(arg, &not_string);
4399 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1);
4400 __ j(below, &done);
4401
4402 // Check the number to string cache.
4403 Label not_cached;
4404 __ bind(&not_string);
4405 // Puts the cached result into scratch1.
4406 NumberToStringStub::GenerateLookupNumberStringCache(masm,
4407 arg,
4408 scratch1,
4409 scratch2,
4410 scratch3,
4411 false,
4412 &not_cached);
4413 __ movq(arg, scratch1);
4414 __ movq(Operand(rsp, stack_offset), arg);
4415 __ jmp(&done);
4416
4417 // Check if the argument is a safe string wrapper.
4418 __ bind(&not_cached);
4419 __ JumpIfSmi(arg, slow);
4420 __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1.
4421 __ j(not_equal, slow);
4422 __ testb(FieldOperand(scratch1, Map::kBitField2Offset),
4423 Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
4424 __ j(zero, slow);
4425 __ movq(arg, FieldOperand(arg, JSValue::kValueOffset));
4426 __ movq(Operand(rsp, stack_offset), arg);
4427
4428 __ bind(&done);
4083 } 4429 }
4084 4430
4085 4431
4086 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, 4432 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
4087 Register dest, 4433 Register dest,
4088 Register src, 4434 Register src,
4089 Register count, 4435 Register count,
4090 bool ascii) { 4436 bool ascii) {
4091 Label loop; 4437 Label loop;
4092 __ bind(&loop); 4438 __ bind(&loop);
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
4203 // Load the symbol table. 4549 // Load the symbol table.
4204 Register symbol_table = c2; 4550 Register symbol_table = c2;
4205 __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex); 4551 __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex);
4206 4552
4207 // Calculate capacity mask from the symbol table capacity. 4553 // Calculate capacity mask from the symbol table capacity.
4208 Register mask = scratch2; 4554 Register mask = scratch2;
4209 __ SmiToInteger32(mask, 4555 __ SmiToInteger32(mask,
4210 FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); 4556 FieldOperand(symbol_table, SymbolTable::kCapacityOffset));
4211 __ decl(mask); 4557 __ decl(mask);
4212 4558
4213 Register undefined = scratch4; 4559 Register map = scratch4;
4214 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
4215 4560
4216 // Registers 4561 // Registers
4217 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 4562 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
4218 // hash: hash of two character string (32-bit int) 4563 // hash: hash of two character string (32-bit int)
4219 // symbol_table: symbol table 4564 // symbol_table: symbol table
4220 // mask: capacity mask (32-bit int) 4565 // mask: capacity mask (32-bit int)
4221 // undefined: undefined value 4566 // map: -
4222 // scratch: - 4567 // scratch: -
4223 4568
4224 // Perform a number of probes in the symbol table. 4569 // Perform a number of probes in the symbol table.
4225 static const int kProbes = 4; 4570 static const int kProbes = 4;
4226 Label found_in_symbol_table; 4571 Label found_in_symbol_table;
4227 Label next_probe[kProbes]; 4572 Label next_probe[kProbes];
4228 for (int i = 0; i < kProbes; i++) { 4573 for (int i = 0; i < kProbes; i++) {
4229 // Calculate entry in symbol table. 4574 // Calculate entry in symbol table.
4230 __ movl(scratch, hash); 4575 __ movl(scratch, hash);
4231 if (i > 0) { 4576 if (i > 0) {
4232 __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i))); 4577 __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i)));
4233 } 4578 }
4234 __ andl(scratch, mask); 4579 __ andl(scratch, mask);
4235 4580
4236 // Load the entry from the symble table. 4581 // Load the entry from the symbol table.
4237 Register candidate = scratch; // Scratch register contains candidate. 4582 Register candidate = scratch; // Scratch register contains candidate.
4238 STATIC_ASSERT(SymbolTable::kEntrySize == 1); 4583 STATIC_ASSERT(SymbolTable::kEntrySize == 1);
4239 __ movq(candidate, 4584 __ movq(candidate,
4240 FieldOperand(symbol_table, 4585 FieldOperand(symbol_table,
4241 scratch, 4586 scratch,
4242 times_pointer_size, 4587 times_pointer_size,
4243 SymbolTable::kElementsStartOffset)); 4588 SymbolTable::kElementsStartOffset));
4244 4589
4245 // If entry is undefined no string with this hash can be found. 4590 // If entry is undefined no string with this hash can be found.
4246 __ cmpq(candidate, undefined); 4591 NearLabel is_string;
4592 __ CmpObjectType(candidate, ODDBALL_TYPE, map);
4593 __ j(not_equal, &is_string);
4594
4595 __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex);
4247 __ j(equal, not_found); 4596 __ j(equal, not_found);
4597 // Must be null (deleted entry).
4598 __ jmp(&next_probe[i]);
4599
4600 __ bind(&is_string);
4248 4601
4249 // If length is not 2 the string is not a candidate. 4602 // If length is not 2 the string is not a candidate.
4250 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), 4603 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset),
4251 Smi::FromInt(2)); 4604 Smi::FromInt(2));
4252 __ j(not_equal, &next_probe[i]); 4605 __ j(not_equal, &next_probe[i]);
4253 4606
4254 // We use kScratchRegister as a temporary register in assumption that 4607 // We use kScratchRegister as a temporary register in assumption that
4255 // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly 4608 // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly
4256 Register temp = kScratchRegister; 4609 Register temp = kScratchRegister;
4257 4610
4258 // Check that the candidate is a non-external ascii string. 4611 // Check that the candidate is a non-external ascii string.
4259 __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset)); 4612 __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset));
4260 __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
4261 __ JumpIfInstanceTypeIsNotSequentialAscii( 4613 __ JumpIfInstanceTypeIsNotSequentialAscii(
4262 temp, temp, &next_probe[i]); 4614 temp, temp, &next_probe[i]);
4263 4615
4264 // Check if the two characters match. 4616 // Check if the two characters match.
4265 __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); 4617 __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize));
4266 __ andl(temp, Immediate(0x0000ffff)); 4618 __ andl(temp, Immediate(0x0000ffff));
4267 __ cmpl(chars, temp); 4619 __ cmpl(chars, temp);
4268 __ j(equal, &found_in_symbol_table); 4620 __ j(equal, &found_in_symbol_table);
4269 __ bind(&next_probe[i]); 4621 __ bind(&next_probe[i]);
4270 } 4622 }
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
4601 __ addq(rsp, Immediate(2 * kPointerSize)); 4953 __ addq(rsp, Immediate(2 * kPointerSize));
4602 __ push(rcx); 4954 __ push(rcx);
4603 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); 4955 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8);
4604 4956
4605 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 4957 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
4606 // tagged as a small integer. 4958 // tagged as a small integer.
4607 __ bind(&runtime); 4959 __ bind(&runtime);
4608 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 4960 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4609 } 4961 }
4610 4962
4963
4611 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { 4964 void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
4612 ASSERT(state_ == CompareIC::SMIS); 4965 ASSERT(state_ == CompareIC::SMIS);
4613 NearLabel miss; 4966 NearLabel miss;
4614 __ JumpIfNotBothSmi(rdx, rax, &miss); 4967 __ JumpIfNotBothSmi(rdx, rax, &miss);
4615 4968
4616 if (GetCondition() == equal) { 4969 if (GetCondition() == equal) {
4617 // For equality we do not care about the sign of the result. 4970 // For equality we do not care about the sign of the result.
4618 __ subq(rax, rdx); 4971 __ subq(rax, rdx);
4619 } else { 4972 } else {
4620 NearLabel done; 4973 NearLabel done;
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
4718 __ pop(rcx); 5071 __ pop(rcx);
4719 __ pop(rax); 5072 __ pop(rax);
4720 __ pop(rdx); 5073 __ pop(rdx);
4721 __ push(rcx); 5074 __ push(rcx);
4722 5075
4723 // Do a tail call to the rewritten stub. 5076 // Do a tail call to the rewritten stub.
4724 __ jmp(rdi); 5077 __ jmp(rdi);
4725 } 5078 }
4726 5079
4727 5080
4728 void GenerateFastPixelArrayLoad(MacroAssembler* masm,
4729 Register receiver,
4730 Register key,
4731 Register elements,
4732 Register untagged_key,
4733 Register result,
4734 Label* not_pixel_array,
4735 Label* key_not_smi,
4736 Label* out_of_range) {
4737 // Register use:
4738 // receiver - holds the receiver and is unchanged.
4739 // key - holds the key and is unchanged (must be a smi).
4740 // elements - is set to the the receiver's element if
4741 // the receiver doesn't have a pixel array or the
4742 // key is not a smi, otherwise it's the elements'
4743 // external pointer.
4744 // untagged_key - is set to the untagged key
4745
4746 // Some callers already have verified that the key is a smi. key_not_smi is
4747 // set to NULL as a sentinel for that case. Otherwise, add an explicit check
4748 // to ensure the key is a smi must be added.
4749 if (key_not_smi != NULL) {
4750 __ JumpIfNotSmi(key, key_not_smi);
4751 } else {
4752 if (FLAG_debug_code) {
4753 __ AbortIfNotSmi(key);
4754 }
4755 }
4756 __ SmiToInteger32(untagged_key, key);
4757
4758 __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
4759 // By passing NULL as not_pixel_array, callers signal that they have already
4760 // verified that the receiver has pixel array elements.
4761 if (not_pixel_array != NULL) {
4762 __ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
4763 } else {
4764 if (FLAG_debug_code) {
4765 // Map check should have already made sure that elements is a pixel array.
4766 __ Cmp(FieldOperand(elements, HeapObject::kMapOffset),
4767 Factory::pixel_array_map());
4768 __ Assert(equal, "Elements isn't a pixel array");
4769 }
4770 }
4771
4772 // Check that the smi is in range.
4773 __ cmpl(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
4774 __ j(above_equal, out_of_range); // unsigned check handles negative keys.
4775
4776 // Load and tag the element as a smi.
4777 __ movq(elements, FieldOperand(elements, PixelArray::kExternalPointerOffset));
4778 __ movzxbq(result, Operand(elements, untagged_key, times_1, 0));
4779 __ Integer32ToSmi(result, result);
4780 __ ret(0);
4781 }
4782
4783
4784 // Stores an indexed element into a pixel array, clamping the stored value.
4785 void GenerateFastPixelArrayStore(MacroAssembler* masm,
4786 Register receiver,
4787 Register key,
4788 Register value,
4789 Register elements,
4790 Register scratch1,
4791 bool load_elements_from_receiver,
4792 bool key_is_untagged,
4793 Label* key_not_smi,
4794 Label* value_not_smi,
4795 Label* not_pixel_array,
4796 Label* out_of_range) {
4797 // Register use:
4798 // receiver - holds the receiver and is unchanged.
4799 // key - holds the key (must be a smi) and is unchanged.
4800 // value - holds the value (must be a smi) and is unchanged.
4801 // elements - holds the element object of the receiver on entry if
4802 // load_elements_from_receiver is false, otherwise used
4803 // internally to store the pixel arrays elements and
4804 // external array pointer.
4805 //
4806 Register external_pointer = elements;
4807 Register untagged_key = scratch1;
4808 Register untagged_value = receiver; // Only set once success guaranteed.
4809
4810 // Fetch the receiver's elements if the caller hasn't already done so.
4811 if (load_elements_from_receiver) {
4812 __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
4813 }
4814
4815 // By passing NULL as not_pixel_array, callers signal that they have already
4816 // verified that the receiver has pixel array elements.
4817 if (not_pixel_array != NULL) {
4818 __ CheckMap(elements, Factory::pixel_array_map(), not_pixel_array, true);
4819 } else {
4820 if (FLAG_debug_code) {
4821 // Map check should have already made sure that elements is a pixel array.
4822 __ Cmp(FieldOperand(elements, HeapObject::kMapOffset),
4823 Factory::pixel_array_map());
4824 __ Assert(equal, "Elements isn't a pixel array");
4825 }
4826 }
4827
4828 // Key must be a smi and it must be in range.
4829 if (key_is_untagged) {
4830 untagged_key = key;
4831 } else {
4832 // Some callers already have verified that the key is a smi. key_not_smi is
4833 // set to NULL as a sentinel for that case. Otherwise, add an explicit
4834 // check to ensure the key is a smi.
4835 if (key_not_smi != NULL) {
4836 __ JumpIfNotSmi(key, key_not_smi);
4837 } else {
4838 if (FLAG_debug_code) {
4839 __ AbortIfNotSmi(key);
4840 }
4841 }
4842 __ SmiToInteger32(untagged_key, key);
4843 }
4844 __ cmpl(untagged_key, FieldOperand(elements, PixelArray::kLengthOffset));
4845 __ j(above_equal, out_of_range); // unsigned check handles negative keys.
4846
4847 // Value must be a smi.
4848 __ JumpIfNotSmi(value, value_not_smi);
4849 __ SmiToInteger32(untagged_value, value);
4850
4851 { // Clamp the value to [0..255].
4852 NearLabel done;
4853 __ testl(untagged_value, Immediate(0xFFFFFF00));
4854 __ j(zero, &done);
4855 __ setcc(negative, untagged_value); // 1 if negative, 0 if positive.
4856 __ decb(untagged_value); // 0 if negative, 255 if positive.
4857 __ bind(&done);
4858 }
4859
4860 __ movq(external_pointer,
4861 FieldOperand(elements, PixelArray::kExternalPointerOffset));
4862 __ movb(Operand(external_pointer, untagged_key, times_1, 0), untagged_value);
4863 __ ret(0); // Return value in eax.
4864 }
4865
4866 #undef __ 5081 #undef __
4867 5082
4868 } } // namespace v8::internal 5083 } } // namespace v8::internal
4869 5084
4870 #endif // V8_TARGET_ARCH_X64 5085 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | src/x64/codegen-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698