| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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, ¬_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(¬_string1); | |
| 1414 __ JumpIfNotString(rhs, rhs, ¬_strings); | |
| 1415 | |
| 1416 // Only second argument is a string. | |
| 1417 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION); | |
| 1418 | |
| 1419 __ bind(¬_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 Loading... |
| 1472 Label not_smi; | 1451 Label not_smi; |
| 1473 | 1452 |
| 1474 GenerateSmiCode(masm, ¬_smi, NO_HEAPNUMBER_RESULTS); | 1453 GenerateSmiCode(masm, ¬_smi, NO_HEAPNUMBER_RESULTS); |
| 1475 | 1454 |
| 1476 __ bind(¬_smi); | 1455 __ bind(¬_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, ¬_number); | 1472 GenerateFloatingPointCode(masm, &gc_required, ¬_number); |
| 1492 | 1473 |
| 1493 __ bind(¬_number); | 1474 __ bind(¬_number); |
| 1494 GenerateTypeTransition(masm); | 1475 GenerateTypeTransition(masm); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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, ¬_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(¬_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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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, ¬_outermost_js); | 3623 __ j(not_zero, ¬_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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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, ¬_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(¬_string); |
| 4405 // Puts the cached result into scratch1. |
| 4406 NumberToStringStub::GenerateLookupNumberStringCache(masm, |
| 4407 arg, |
| 4408 scratch1, |
| 4409 scratch2, |
| 4410 scratch3, |
| 4411 false, |
| 4412 ¬_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(¬_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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |