| 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 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 Register dst, | 198 Register dst, |
| 199 SaveFPRegsMode save_fp, | 199 SaveFPRegsMode save_fp, |
| 200 RememberedSetAction remembered_set_action, | 200 RememberedSetAction remembered_set_action, |
| 201 SmiCheck smi_check) { | 201 SmiCheck smi_check) { |
| 202 // First, check if a write barrier is even needed. The tests below | 202 // First, check if a write barrier is even needed. The tests below |
| 203 // catch stores of Smis. | 203 // catch stores of Smis. |
| 204 Label done; | 204 Label done; |
| 205 | 205 |
| 206 // Skip barrier if writing a smi. | 206 // Skip barrier if writing a smi. |
| 207 if (smi_check == INLINE_SMI_CHECK) { | 207 if (smi_check == INLINE_SMI_CHECK) { |
| 208 ASSERT_EQ(0, kSmiTag); | 208 JumpIfSmi(value, &done, Label::kNear); |
| 209 test(value, Immediate(kSmiTagMask)); | |
| 210 j(zero, &done, Label::kNear); | |
| 211 } | 209 } |
| 212 | 210 |
| 213 // Although the object register is tagged, the offset is relative to the start | 211 // Although the object register is tagged, the offset is relative to the start |
| 214 // of the object, so so offset must be a multiple of kPointerSize. | 212 // of the object, so so offset must be a multiple of kPointerSize. |
| 215 ASSERT(IsAligned(offset, kPointerSize)); | 213 ASSERT(IsAligned(offset, kPointerSize)); |
| 216 | 214 |
| 217 lea(dst, FieldOperand(object, offset)); | 215 lea(dst, FieldOperand(object, offset)); |
| 218 if (emit_debug_code()) { | 216 if (emit_debug_code()) { |
| 219 Label ok; | 217 Label ok; |
| 220 test_b(Operand(dst), (1 << kPointerSizeLog2) - 1); | 218 test_b(Operand(dst), (1 << kPointerSizeLog2) - 1); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 int3(); | 260 int3(); |
| 263 bind(&ok); | 261 bind(&ok); |
| 264 } | 262 } |
| 265 | 263 |
| 266 // First, check if a write barrier is even needed. The tests below | 264 // First, check if a write barrier is even needed. The tests below |
| 267 // catch stores of Smis and stores into young gen. | 265 // catch stores of Smis and stores into young gen. |
| 268 Label done; | 266 Label done; |
| 269 | 267 |
| 270 if (smi_check == INLINE_SMI_CHECK) { | 268 if (smi_check == INLINE_SMI_CHECK) { |
| 271 // Skip barrier if writing a smi. | 269 // Skip barrier if writing a smi. |
| 272 ASSERT_EQ(0, kSmiTag); | 270 JumpIfSmi(value, &done, Label::kNear); |
| 273 test(value, Immediate(kSmiTagMask)); | |
| 274 j(zero, &done, Label::kNear); | |
| 275 } | 271 } |
| 276 | 272 |
| 277 CheckPageFlag(value, | 273 CheckPageFlag(value, |
| 278 value, // Used as scratch. | 274 value, // Used as scratch. |
| 279 MemoryChunk::kPointersToHereAreInterestingMask, | 275 MemoryChunk::kPointersToHereAreInterestingMask, |
| 280 zero, | 276 zero, |
| 281 &done, | 277 &done, |
| 282 Label::kNear); | 278 Label::kNear); |
| 283 CheckPageFlag(object, | 279 CheckPageFlag(object, |
| 284 value, // Used as scratch. | 280 value, // Used as scratch. |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 CmpInstanceType(map, type); | 355 CmpInstanceType(map, type); |
| 360 } | 356 } |
| 361 | 357 |
| 362 | 358 |
| 363 void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { | 359 void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { |
| 364 cmpb(FieldOperand(map, Map::kInstanceTypeOffset), | 360 cmpb(FieldOperand(map, Map::kInstanceTypeOffset), |
| 365 static_cast<int8_t>(type)); | 361 static_cast<int8_t>(type)); |
| 366 } | 362 } |
| 367 | 363 |
| 368 | 364 |
| 365 void MacroAssembler::CheckFastElements(Register map, |
| 366 Label* fail, |
| 367 Label::Distance distance) { |
| 368 STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); |
| 369 cmpb(FieldOperand(map, Map::kBitField2Offset), |
| 370 Map::kMaximumBitField2FastElementValue); |
| 371 j(above, fail, distance); |
| 372 } |
| 373 |
| 374 |
| 369 void MacroAssembler::CheckMap(Register obj, | 375 void MacroAssembler::CheckMap(Register obj, |
| 370 Handle<Map> map, | 376 Handle<Map> map, |
| 371 Label* fail, | 377 Label* fail, |
| 372 SmiCheckType smi_check_type) { | 378 SmiCheckType smi_check_type) { |
| 373 if (smi_check_type == DO_SMI_CHECK) { | 379 if (smi_check_type == DO_SMI_CHECK) { |
| 374 JumpIfSmi(obj, fail); | 380 JumpIfSmi(obj, fail); |
| 375 } | 381 } |
| 376 cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map)); | 382 cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map)); |
| 377 j(not_equal, fail); | 383 j(not_equal, fail); |
| 378 } | 384 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 Label* fail) { | 416 Label* fail) { |
| 411 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); | 417 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); |
| 412 IsInstanceJSObjectType(map, scratch, fail); | 418 IsInstanceJSObjectType(map, scratch, fail); |
| 413 } | 419 } |
| 414 | 420 |
| 415 | 421 |
| 416 void MacroAssembler::IsInstanceJSObjectType(Register map, | 422 void MacroAssembler::IsInstanceJSObjectType(Register map, |
| 417 Register scratch, | 423 Register scratch, |
| 418 Label* fail) { | 424 Label* fail) { |
| 419 movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset)); | 425 movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset)); |
| 420 sub(Operand(scratch), Immediate(FIRST_JS_OBJECT_TYPE)); | 426 sub(Operand(scratch), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 421 cmp(scratch, LAST_JS_OBJECT_TYPE - FIRST_JS_OBJECT_TYPE); | 427 cmp(scratch, |
| 428 LAST_NONCALLABLE_SPEC_OBJECT_TYPE - FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 422 j(above, fail); | 429 j(above, fail); |
| 423 } | 430 } |
| 424 | 431 |
| 425 | 432 |
| 426 void MacroAssembler::FCmp() { | 433 void MacroAssembler::FCmp() { |
| 427 if (CpuFeatures::IsSupported(CMOV)) { | 434 if (CpuFeatures::IsSupported(CMOV)) { |
| 428 fucomip(); | 435 fucomip(); |
| 429 ffree(0); | 436 ffree(0); |
| 430 fincstp(); | 437 fincstp(); |
| 431 } else { | 438 } else { |
| 432 fucompp(); | 439 fucompp(); |
| 433 push(eax); | 440 push(eax); |
| 434 fnstsw_ax(); | 441 fnstsw_ax(); |
| 435 sahf(); | 442 sahf(); |
| 436 pop(eax); | 443 pop(eax); |
| 437 } | 444 } |
| 438 } | 445 } |
| 439 | 446 |
| 440 | 447 |
| 441 void MacroAssembler::AbortIfNotNumber(Register object) { | 448 void MacroAssembler::AbortIfNotNumber(Register object) { |
| 442 Label ok; | 449 Label ok; |
| 443 test(object, Immediate(kSmiTagMask)); | 450 JumpIfSmi(object, &ok); |
| 444 j(zero, &ok); | |
| 445 cmp(FieldOperand(object, HeapObject::kMapOffset), | 451 cmp(FieldOperand(object, HeapObject::kMapOffset), |
| 446 isolate()->factory()->heap_number_map()); | 452 isolate()->factory()->heap_number_map()); |
| 447 Assert(equal, "Operand not a number"); | 453 Assert(equal, "Operand not a number"); |
| 448 bind(&ok); | 454 bind(&ok); |
| 449 } | 455 } |
| 450 | 456 |
| 451 | 457 |
| 452 void MacroAssembler::AbortIfNotSmi(Register object) { | 458 void MacroAssembler::AbortIfNotSmi(Register object) { |
| 453 test(object, Immediate(kSmiTagMask)); | 459 test(object, Immediate(kSmiTagMask)); |
| 454 Assert(equal, "Operand is not a smi"); | 460 Assert(equal, "Operand is not a smi"); |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 806 Context::SECURITY_TOKEN_INDEX * kPointerSize; | 812 Context::SECURITY_TOKEN_INDEX * kPointerSize; |
| 807 mov(scratch, FieldOperand(scratch, token_offset)); | 813 mov(scratch, FieldOperand(scratch, token_offset)); |
| 808 cmp(scratch, FieldOperand(holder_reg, token_offset)); | 814 cmp(scratch, FieldOperand(holder_reg, token_offset)); |
| 809 pop(holder_reg); | 815 pop(holder_reg); |
| 810 j(not_equal, miss); | 816 j(not_equal, miss); |
| 811 | 817 |
| 812 bind(&same_contexts); | 818 bind(&same_contexts); |
| 813 } | 819 } |
| 814 | 820 |
| 815 | 821 |
| 822 void MacroAssembler::LoadFromNumberDictionary(Label* miss, |
| 823 Register elements, |
| 824 Register key, |
| 825 Register r0, |
| 826 Register r1, |
| 827 Register r2, |
| 828 Register result) { |
| 829 // Register use: |
| 830 // |
| 831 // elements - holds the slow-case elements of the receiver and is unchanged. |
| 832 // |
| 833 // key - holds the smi key on entry and is unchanged. |
| 834 // |
| 835 // Scratch registers: |
| 836 // |
| 837 // r0 - holds the untagged key on entry and holds the hash once computed. |
| 838 // |
| 839 // r1 - used to hold the capacity mask of the dictionary |
| 840 // |
| 841 // r2 - used for the index into the dictionary. |
| 842 // |
| 843 // result - holds the result on exit if the load succeeds and we fall through. |
| 844 |
| 845 Label done; |
| 846 |
| 847 // Compute the hash code from the untagged key. This must be kept in sync |
| 848 // with ComputeIntegerHash in utils.h. |
| 849 // |
| 850 // hash = ~hash + (hash << 15); |
| 851 mov(r1, r0); |
| 852 not_(r0); |
| 853 shl(r1, 15); |
| 854 add(r0, Operand(r1)); |
| 855 // hash = hash ^ (hash >> 12); |
| 856 mov(r1, r0); |
| 857 shr(r1, 12); |
| 858 xor_(r0, Operand(r1)); |
| 859 // hash = hash + (hash << 2); |
| 860 lea(r0, Operand(r0, r0, times_4, 0)); |
| 861 // hash = hash ^ (hash >> 4); |
| 862 mov(r1, r0); |
| 863 shr(r1, 4); |
| 864 xor_(r0, Operand(r1)); |
| 865 // hash = hash * 2057; |
| 866 imul(r0, r0, 2057); |
| 867 // hash = hash ^ (hash >> 16); |
| 868 mov(r1, r0); |
| 869 shr(r1, 16); |
| 870 xor_(r0, Operand(r1)); |
| 871 |
| 872 // Compute capacity mask. |
| 873 mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset)); |
| 874 shr(r1, kSmiTagSize); // convert smi to int |
| 875 dec(r1); |
| 876 |
| 877 // Generate an unrolled loop that performs a few probes before giving up. |
| 878 const int kProbes = 4; |
| 879 for (int i = 0; i < kProbes; i++) { |
| 880 // Use r2 for index calculations and keep the hash intact in r0. |
| 881 mov(r2, r0); |
| 882 // Compute the masked index: (hash + i + i * i) & mask. |
| 883 if (i > 0) { |
| 884 add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i))); |
| 885 } |
| 886 and_(r2, Operand(r1)); |
| 887 |
| 888 // Scale the index by multiplying by the entry size. |
| 889 ASSERT(NumberDictionary::kEntrySize == 3); |
| 890 lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 |
| 891 |
| 892 // Check if the key matches. |
| 893 cmp(key, FieldOperand(elements, |
| 894 r2, |
| 895 times_pointer_size, |
| 896 NumberDictionary::kElementsStartOffset)); |
| 897 if (i != (kProbes - 1)) { |
| 898 j(equal, &done); |
| 899 } else { |
| 900 j(not_equal, miss); |
| 901 } |
| 902 } |
| 903 |
| 904 bind(&done); |
| 905 // Check that the value is a normal propety. |
| 906 const int kDetailsOffset = |
| 907 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
| 908 ASSERT_EQ(NORMAL, 0); |
| 909 test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), |
| 910 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
| 911 j(not_zero, miss); |
| 912 |
| 913 // Get the value at the masked, scaled index. |
| 914 const int kValueOffset = |
| 915 NumberDictionary::kElementsStartOffset + kPointerSize; |
| 916 mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); |
| 917 } |
| 918 |
| 919 |
| 816 void MacroAssembler::LoadAllocationTopHelper(Register result, | 920 void MacroAssembler::LoadAllocationTopHelper(Register result, |
| 817 Register scratch, | 921 Register scratch, |
| 818 AllocationFlags flags) { | 922 AllocationFlags flags) { |
| 819 ExternalReference new_space_allocation_top = | 923 ExternalReference new_space_allocation_top = |
| 820 ExternalReference::new_space_allocation_top_address(isolate()); | 924 ExternalReference::new_space_allocation_top_address(isolate()); |
| 821 | 925 |
| 822 // Just return if allocation top is already known. | 926 // Just return if allocation top is already known. |
| 823 if ((flags & RESULT_CONTAINS_TOP) != 0) { | 927 if ((flags & RESULT_CONTAINS_TOP) != 0) { |
| 824 // No use of scratch if allocation top is provided. | 928 // No use of scratch if allocation top is provided. |
| 825 ASSERT(scratch.is(no_reg)); | 929 ASSERT(scratch.is(no_reg)); |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1245 j(sign, then_label); | 1349 j(sign, then_label); |
| 1246 bind(&ok); | 1350 bind(&ok); |
| 1247 } | 1351 } |
| 1248 | 1352 |
| 1249 | 1353 |
| 1250 void MacroAssembler::TryGetFunctionPrototype(Register function, | 1354 void MacroAssembler::TryGetFunctionPrototype(Register function, |
| 1251 Register result, | 1355 Register result, |
| 1252 Register scratch, | 1356 Register scratch, |
| 1253 Label* miss) { | 1357 Label* miss) { |
| 1254 // Check that the receiver isn't a smi. | 1358 // Check that the receiver isn't a smi. |
| 1255 test(function, Immediate(kSmiTagMask)); | 1359 JumpIfSmi(function, miss); |
| 1256 j(zero, miss); | |
| 1257 | 1360 |
| 1258 // Check that the function really is a function. | 1361 // Check that the function really is a function. |
| 1259 CmpObjectType(function, JS_FUNCTION_TYPE, result); | 1362 CmpObjectType(function, JS_FUNCTION_TYPE, result); |
| 1260 j(not_equal, miss); | 1363 j(not_equal, miss); |
| 1261 | 1364 |
| 1262 // Make sure that the function has an instance prototype. | 1365 // Make sure that the function has an instance prototype. |
| 1263 Label non_instance; | 1366 Label non_instance; |
| 1264 movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset)); | 1367 movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset)); |
| 1265 test(scratch, Immediate(1 << Map::kHasNonInstancePrototype)); | 1368 test(scratch, Immediate(1 << Map::kHasNonInstancePrototype)); |
| 1266 j(not_zero, &non_instance); | 1369 j(not_zero, &non_instance); |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1485 static const bool kReturnHandlesDirectly = false; | 1588 static const bool kReturnHandlesDirectly = false; |
| 1486 #endif | 1589 #endif |
| 1487 | 1590 |
| 1488 | 1591 |
| 1489 Operand ApiParameterOperand(int index) { | 1592 Operand ApiParameterOperand(int index) { |
| 1490 return Operand( | 1593 return Operand( |
| 1491 esp, (index + (kReturnHandlesDirectly ? 0 : 1)) * kPointerSize); | 1594 esp, (index + (kReturnHandlesDirectly ? 0 : 1)) * kPointerSize); |
| 1492 } | 1595 } |
| 1493 | 1596 |
| 1494 | 1597 |
| 1495 void MacroAssembler::PrepareCallApiFunction(int argc, Register scratch) { | 1598 void MacroAssembler::PrepareCallApiFunction(int argc) { |
| 1496 if (kReturnHandlesDirectly) { | 1599 if (kReturnHandlesDirectly) { |
| 1497 EnterApiExitFrame(argc); | 1600 EnterApiExitFrame(argc); |
| 1498 // When handles are returned directly we don't have to allocate extra | 1601 // When handles are returned directly we don't have to allocate extra |
| 1499 // space for and pass an out parameter. | 1602 // space for and pass an out parameter. |
| 1603 if (emit_debug_code()) { |
| 1604 mov(esi, Immediate(BitCast<int32_t>(kZapValue))); |
| 1605 } |
| 1500 } else { | 1606 } else { |
| 1501 // We allocate two additional slots: return value and pointer to it. | 1607 // We allocate two additional slots: return value and pointer to it. |
| 1502 EnterApiExitFrame(argc + 2); | 1608 EnterApiExitFrame(argc + 2); |
| 1503 | 1609 |
| 1504 // The argument slots are filled as follows: | 1610 // The argument slots are filled as follows: |
| 1505 // | 1611 // |
| 1506 // n + 1: output cell | 1612 // n + 1: output slot |
| 1507 // n: arg n | 1613 // n: arg n |
| 1508 // ... | 1614 // ... |
| 1509 // 1: arg1 | 1615 // 1: arg1 |
| 1510 // 0: pointer to the output cell | 1616 // 0: pointer to the output slot |
| 1511 // | |
| 1512 // Note that this is one more "argument" than the function expects | |
| 1513 // so the out cell will have to be popped explicitly after returning | |
| 1514 // from the function. The out cell contains Handle. | |
| 1515 | 1617 |
| 1516 // pointer to out cell. | 1618 lea(esi, Operand(esp, (argc + 1) * kPointerSize)); |
| 1517 lea(scratch, Operand(esp, (argc + 1) * kPointerSize)); | 1619 mov(Operand(esp, 0 * kPointerSize), esi); |
| 1518 mov(Operand(esp, 0 * kPointerSize), scratch); // output. | |
| 1519 if (emit_debug_code()) { | 1620 if (emit_debug_code()) { |
| 1520 mov(Operand(esp, (argc + 1) * kPointerSize), Immediate(0)); // out cell. | 1621 mov(Operand(esi, 0), Immediate(0)); |
| 1521 } | 1622 } |
| 1522 } | 1623 } |
| 1523 } | 1624 } |
| 1524 | 1625 |
| 1525 | 1626 |
| 1526 MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, | 1627 MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, |
| 1527 int stack_space) { | 1628 int stack_space) { |
| 1528 ExternalReference next_address = | 1629 ExternalReference next_address = |
| 1529 ExternalReference::handle_scope_next_address(); | 1630 ExternalReference::handle_scope_next_address(); |
| 1530 ExternalReference limit_address = | 1631 ExternalReference limit_address = |
| 1531 ExternalReference::handle_scope_limit_address(); | 1632 ExternalReference::handle_scope_limit_address(); |
| 1532 ExternalReference level_address = | 1633 ExternalReference level_address = |
| 1533 ExternalReference::handle_scope_level_address(); | 1634 ExternalReference::handle_scope_level_address(); |
| 1534 | 1635 |
| 1535 // Allocate HandleScope in callee-save registers. | 1636 // Allocate HandleScope in callee-save registers. |
| 1536 mov(ebx, Operand::StaticVariable(next_address)); | 1637 mov(ebx, Operand::StaticVariable(next_address)); |
| 1537 mov(edi, Operand::StaticVariable(limit_address)); | 1638 mov(edi, Operand::StaticVariable(limit_address)); |
| 1538 add(Operand::StaticVariable(level_address), Immediate(1)); | 1639 add(Operand::StaticVariable(level_address), Immediate(1)); |
| 1539 | 1640 |
| 1540 // Call the api function! | 1641 // Call the api function! |
| 1541 call(function->address(), RelocInfo::RUNTIME_ENTRY); | 1642 call(function->address(), RelocInfo::RUNTIME_ENTRY); |
| 1542 | 1643 |
| 1543 if (!kReturnHandlesDirectly) { | 1644 if (!kReturnHandlesDirectly) { |
| 1544 // The returned value is a pointer to the handle holding the result. | 1645 // PrepareCallApiFunction saved pointer to the output slot into |
| 1545 // Dereference this to get to the location. | 1646 // callee-save register esi. |
| 1546 mov(eax, Operand(eax, 0)); | 1647 mov(eax, Operand(esi, 0)); |
| 1547 } | 1648 } |
| 1548 | 1649 |
| 1549 Label empty_handle; | 1650 Label empty_handle; |
| 1550 Label prologue; | 1651 Label prologue; |
| 1551 Label promote_scheduled_exception; | 1652 Label promote_scheduled_exception; |
| 1552 Label delete_allocated_handles; | 1653 Label delete_allocated_handles; |
| 1553 Label leave_exit_frame; | 1654 Label leave_exit_frame; |
| 1554 | 1655 |
| 1555 // Check if the result handle holds 0. | 1656 // Check if the result handle holds 0. |
| 1556 test(eax, Operand(eax)); | 1657 test(eax, Operand(eax)); |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1770 | 1871 |
| 1771 ParameterCount expected(ebx); | 1872 ParameterCount expected(ebx); |
| 1772 InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), | 1873 InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), |
| 1773 expected, actual, flag, call_wrapper, call_kind); | 1874 expected, actual, flag, call_wrapper, call_kind); |
| 1774 } | 1875 } |
| 1775 | 1876 |
| 1776 | 1877 |
| 1777 void MacroAssembler::InvokeFunction(JSFunction* function, | 1878 void MacroAssembler::InvokeFunction(JSFunction* function, |
| 1778 const ParameterCount& actual, | 1879 const ParameterCount& actual, |
| 1779 InvokeFlag flag, | 1880 InvokeFlag flag, |
| 1780 const CallWrapper& call_wrapper) { | 1881 const CallWrapper& call_wrapper, |
| 1882 CallKind call_kind) { |
| 1781 ASSERT(function->is_compiled()); | 1883 ASSERT(function->is_compiled()); |
| 1782 // Get the function and setup the context. | 1884 // Get the function and setup the context. |
| 1783 mov(edi, Immediate(Handle<JSFunction>(function))); | 1885 mov(edi, Immediate(Handle<JSFunction>(function))); |
| 1784 mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 1886 mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 1785 | 1887 |
| 1786 ParameterCount expected(function->shared()->formal_parameter_count()); | 1888 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 1787 if (V8::UseCrankshaft()) { | 1889 if (V8::UseCrankshaft()) { |
| 1788 // TODO(kasperl): For now, we always call indirectly through the | 1890 // TODO(kasperl): For now, we always call indirectly through the |
| 1789 // code field in the function to allow recompilation to take effect | 1891 // code field in the function to allow recompilation to take effect |
| 1790 // without changing any of the call sites. | 1892 // without changing any of the call sites. |
| 1791 InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), | 1893 InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), |
| 1792 expected, actual, flag, call_wrapper); | 1894 expected, actual, flag, call_wrapper, call_kind); |
| 1793 } else { | 1895 } else { |
| 1794 Handle<Code> code(function->code()); | 1896 Handle<Code> code(function->code()); |
| 1795 InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, | 1897 InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, |
| 1796 flag, call_wrapper); | 1898 flag, call_wrapper, call_kind); |
| 1797 } | 1899 } |
| 1798 } | 1900 } |
| 1799 | 1901 |
| 1800 | 1902 |
| 1801 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, | 1903 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, |
| 1802 InvokeFlag flag, | 1904 InvokeFlag flag, |
| 1803 const CallWrapper& call_wrapper) { | 1905 const CallWrapper& call_wrapper) { |
| 1804 // Calls are not allowed in some stubs. | 1906 // Calls are not allowed in some stubs. |
| 1805 ASSERT(flag == JUMP_FUNCTION || allow_stub_calls()); | 1907 ASSERT(flag == JUMP_FUNCTION || allow_stub_calls()); |
| 1806 | 1908 |
| 1807 // Rely on the assertion to check that the number of provided | 1909 // Rely on the assertion to check that the number of provided |
| 1808 // arguments match the expected number of arguments. Fake a | 1910 // arguments match the expected number of arguments. Fake a |
| 1809 // parameter count to avoid emitting code to do the check. | 1911 // parameter count to avoid emitting code to do the check. |
| 1810 ParameterCount expected(0); | 1912 ParameterCount expected(0); |
| 1811 GetBuiltinFunction(edi, id); | 1913 GetBuiltinFunction(edi, id); |
| 1812 InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), | 1914 InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), |
| 1813 expected, expected, flag, call_wrapper); | 1915 expected, expected, flag, call_wrapper, CALL_AS_METHOD); |
| 1814 } | 1916 } |
| 1815 | 1917 |
| 1816 void MacroAssembler::GetBuiltinFunction(Register target, | 1918 void MacroAssembler::GetBuiltinFunction(Register target, |
| 1817 Builtins::JavaScript id) { | 1919 Builtins::JavaScript id) { |
| 1818 // Load the JavaScript builtin function from the builtins object. | 1920 // Load the JavaScript builtin function from the builtins object. |
| 1819 mov(target, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 1921 mov(target, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 1820 mov(target, FieldOperand(target, GlobalObject::kBuiltinsOffset)); | 1922 mov(target, FieldOperand(target, GlobalObject::kBuiltinsOffset)); |
| 1821 mov(target, FieldOperand(target, | 1923 mov(target, FieldOperand(target, |
| 1822 JSBuiltinsObject::OffsetOfFunctionWithId(id))); | 1924 JSBuiltinsObject::OffsetOfFunctionWithId(id))); |
| 1823 } | 1925 } |
| 1824 | 1926 |
| 1825 void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { | 1927 void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { |
| 1826 ASSERT(!target.is(edi)); | 1928 ASSERT(!target.is(edi)); |
| 1827 // Load the JavaScript builtin function from the builtins object. | 1929 // Load the JavaScript builtin function from the builtins object. |
| 1828 GetBuiltinFunction(edi, id); | 1930 GetBuiltinFunction(edi, id); |
| 1829 // Load the code entry point from the function into the target register. | 1931 // Load the code entry point from the function into the target register. |
| 1830 mov(target, FieldOperand(edi, JSFunction::kCodeEntryOffset)); | 1932 mov(target, FieldOperand(edi, JSFunction::kCodeEntryOffset)); |
| 1831 } | 1933 } |
| 1832 | 1934 |
| 1833 | 1935 |
| 1834 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { | 1936 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { |
| 1835 if (context_chain_length > 0) { | 1937 if (context_chain_length > 0) { |
| 1836 // Move up the chain of contexts to the context containing the slot. | 1938 // Move up the chain of contexts to the context containing the slot. |
| 1837 mov(dst, Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX))); | 1939 mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 1838 // Load the function context (which is the incoming, outer context). | |
| 1839 mov(dst, FieldOperand(dst, JSFunction::kContextOffset)); | |
| 1840 for (int i = 1; i < context_chain_length; i++) { | 1940 for (int i = 1; i < context_chain_length; i++) { |
| 1841 mov(dst, Operand(dst, Context::SlotOffset(Context::CLOSURE_INDEX))); | 1941 mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 1842 mov(dst, FieldOperand(dst, JSFunction::kContextOffset)); | |
| 1843 } | 1942 } |
| 1844 } else { | 1943 } else { |
| 1845 // Slot is in the current function context. Move it into the | 1944 // Slot is in the current function context. Move it into the |
| 1846 // destination register in case we store into it (the write barrier | 1945 // destination register in case we store into it (the write barrier |
| 1847 // cannot be allowed to destroy the context in esi). | 1946 // cannot be allowed to destroy the context in esi). |
| 1848 mov(dst, esi); | 1947 mov(dst, esi); |
| 1849 } | 1948 } |
| 1850 | 1949 |
| 1851 // We should not have found a 'with' context by walking the context chain | 1950 // We should not have found a with context by walking the context chain |
| 1852 // (i.e., the static scope chain and runtime context chain do not agree). | 1951 // (i.e., the static scope chain and runtime context chain do not agree). |
| 1853 // A variable occurring in such a scope should have slot type LOOKUP and | 1952 // A variable occurring in such a scope should have slot type LOOKUP and |
| 1854 // not CONTEXT. | 1953 // not CONTEXT. |
| 1855 if (emit_debug_code()) { | 1954 if (emit_debug_code()) { |
| 1856 cmp(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 1955 cmp(FieldOperand(dst, HeapObject::kMapOffset), |
| 1857 Check(equal, "Yo dawg, I heard you liked function contexts " | 1956 isolate()->factory()->with_context_map()); |
| 1858 "so I put function contexts in all your contexts"); | 1957 Check(not_equal, "Variable resolved to with context."); |
| 1859 } | 1958 } |
| 1860 } | 1959 } |
| 1861 | 1960 |
| 1862 | 1961 |
| 1863 void MacroAssembler::LoadGlobalFunction(int index, Register function) { | 1962 void MacroAssembler::LoadGlobalFunction(int index, Register function) { |
| 1864 // Load the global or builtins object from the current context. | 1963 // Load the global or builtins object from the current context. |
| 1865 mov(function, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 1964 mov(function, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 1866 // Load the global context from the global or builtins object. | 1965 // Load the global context from the global or builtins object. |
| 1867 mov(function, FieldOperand(function, GlobalObject::kGlobalContextOffset)); | 1966 mov(function, FieldOperand(function, GlobalObject::kGlobalContextOffset)); |
| 1868 // Load the function from the global context. | 1967 // Load the function from the global context. |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2127 | 2226 |
| 2128 void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1, | 2227 void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1, |
| 2129 Register object2, | 2228 Register object2, |
| 2130 Register scratch1, | 2229 Register scratch1, |
| 2131 Register scratch2, | 2230 Register scratch2, |
| 2132 Label* failure) { | 2231 Label* failure) { |
| 2133 // Check that both objects are not smis. | 2232 // Check that both objects are not smis. |
| 2134 ASSERT_EQ(0, kSmiTag); | 2233 ASSERT_EQ(0, kSmiTag); |
| 2135 mov(scratch1, Operand(object1)); | 2234 mov(scratch1, Operand(object1)); |
| 2136 and_(scratch1, Operand(object2)); | 2235 and_(scratch1, Operand(object2)); |
| 2137 test(scratch1, Immediate(kSmiTagMask)); | 2236 JumpIfSmi(scratch1, failure); |
| 2138 j(zero, failure); | |
| 2139 | 2237 |
| 2140 // Load instance type for both strings. | 2238 // Load instance type for both strings. |
| 2141 mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset)); | 2239 mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset)); |
| 2142 mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset)); | 2240 mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset)); |
| 2143 movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); | 2241 movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset)); |
| 2144 movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); | 2242 movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset)); |
| 2145 | 2243 |
| 2146 // Check that both are flat ascii strings. | 2244 // Check that both are flat ascii strings. |
| 2147 const int kFlatAsciiStringMask = | 2245 const int kFlatAsciiStringMask = |
| 2148 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; | 2246 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask; |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2414 and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask)); | 2512 and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask)); |
| 2415 add(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset), | 2513 add(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset), |
| 2416 length); | 2514 length); |
| 2417 | 2515 |
| 2418 bind(&done); | 2516 bind(&done); |
| 2419 } | 2517 } |
| 2420 | 2518 |
| 2421 } } // namespace v8::internal | 2519 } } // namespace v8::internal |
| 2422 | 2520 |
| 2423 #endif // V8_TARGET_ARCH_IA32 | 2521 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |