OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 return (allocator()->count(rax) == (frame()->is_used(rax) ? 1 : 0)) | 530 return (allocator()->count(rax) == (frame()->is_used(rax) ? 1 : 0)) |
531 && (allocator()->count(rbx) == (frame()->is_used(rbx) ? 1 : 0)) | 531 && (allocator()->count(rbx) == (frame()->is_used(rbx) ? 1 : 0)) |
532 && (allocator()->count(rcx) == (frame()->is_used(rcx) ? 1 : 0)) | 532 && (allocator()->count(rcx) == (frame()->is_used(rcx) ? 1 : 0)) |
533 && (allocator()->count(rdx) == (frame()->is_used(rdx) ? 1 : 0)) | 533 && (allocator()->count(rdx) == (frame()->is_used(rdx) ? 1 : 0)) |
534 && (allocator()->count(rdi) == (frame()->is_used(rdi) ? 1 : 0)) | 534 && (allocator()->count(rdi) == (frame()->is_used(rdi) ? 1 : 0)) |
535 && (allocator()->count(r8) == (frame()->is_used(r8) ? 1 : 0)) | 535 && (allocator()->count(r8) == (frame()->is_used(r8) ? 1 : 0)) |
536 && (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0)) | 536 && (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0)) |
537 && (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0)) | 537 && (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0)) |
538 && (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0)) | 538 && (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0)) |
539 && (allocator()->count(r15) == (frame()->is_used(r15) ? 1 : 0)) | 539 && (allocator()->count(r15) == (frame()->is_used(r15) ? 1 : 0)) |
540 && (allocator()->count(r13) == (frame()->is_used(r13) ? 1 : 0)) | |
541 && (allocator()->count(r12) == (frame()->is_used(r12) ? 1 : 0)); | 540 && (allocator()->count(r12) == (frame()->is_used(r12) ? 1 : 0)); |
542 } | 541 } |
543 #endif | 542 #endif |
544 | 543 |
545 | 544 |
546 class DeferredReferenceGetKeyedValue: public DeferredCode { | 545 class DeferredReferenceGetKeyedValue: public DeferredCode { |
547 public: | 546 public: |
548 explicit DeferredReferenceGetKeyedValue(Register dst, | 547 explicit DeferredReferenceGetKeyedValue(Register dst, |
549 Register receiver, | 548 Register receiver, |
550 Register key, | 549 Register key, |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 | 850 |
852 void DeferredStackCheck::Generate() { | 851 void DeferredStackCheck::Generate() { |
853 StackCheckStub stub; | 852 StackCheckStub stub; |
854 __ CallStub(&stub); | 853 __ CallStub(&stub); |
855 } | 854 } |
856 | 855 |
857 | 856 |
858 void CodeGenerator::CheckStack() { | 857 void CodeGenerator::CheckStack() { |
859 if (FLAG_check_stack) { | 858 if (FLAG_check_stack) { |
860 DeferredStackCheck* deferred = new DeferredStackCheck; | 859 DeferredStackCheck* deferred = new DeferredStackCheck; |
861 ExternalReference stack_guard_limit = | 860 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
862 ExternalReference::address_of_stack_guard_limit(); | |
863 __ movq(kScratchRegister, stack_guard_limit); | |
864 __ cmpq(rsp, Operand(kScratchRegister, 0)); | |
865 deferred->Branch(below); | 861 deferred->Branch(below); |
866 deferred->BindExit(); | 862 deferred->BindExit(); |
867 } | 863 } |
868 } | 864 } |
869 | 865 |
870 | 866 |
871 void CodeGenerator::VisitAndSpill(Statement* statement) { | 867 void CodeGenerator::VisitAndSpill(Statement* statement) { |
872 // TODO(X64): No architecture specific code. Move to shared location. | 868 // TODO(X64): No architecture specific code. Move to shared location. |
873 ASSERT(in_spilled_code()); | 869 ASSERT(in_spilled_code()); |
874 set_in_spilled_code(false); | 870 set_in_spilled_code(false); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
934 frame_->EmitPush(kScratchRegister); | 930 frame_->EmitPush(kScratchRegister); |
935 // Declaration nodes are always introduced in one of two modes. | 931 // Declaration nodes are always introduced in one of two modes. |
936 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); | 932 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
937 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 933 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
938 frame_->EmitPush(Immediate(Smi::FromInt(attr))); | 934 frame_->EmitPush(Immediate(Smi::FromInt(attr))); |
939 // Push initial value, if any. | 935 // Push initial value, if any. |
940 // Note: For variables we must not push an initial value (such as | 936 // Note: For variables we must not push an initial value (such as |
941 // 'undefined') because we may have a (legal) redeclaration and we | 937 // 'undefined') because we may have a (legal) redeclaration and we |
942 // must not destroy the current value. | 938 // must not destroy the current value. |
943 if (node->mode() == Variable::CONST) { | 939 if (node->mode() == Variable::CONST) { |
944 __ movq(kScratchRegister, Factory::the_hole_value(), | 940 frame_->EmitPush(Heap::kTheHoleValueRootIndex); |
945 RelocInfo::EMBEDDED_OBJECT); | |
946 frame_->EmitPush(kScratchRegister); | |
947 } else if (node->fun() != NULL) { | 941 } else if (node->fun() != NULL) { |
948 Load(node->fun()); | 942 Load(node->fun()); |
949 } else { | 943 } else { |
950 frame_->EmitPush(Immediate(Smi::FromInt(0))); // no initial value! | 944 frame_->EmitPush(Immediate(Smi::FromInt(0))); // no initial value! |
951 } | 945 } |
952 Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); | 946 Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); |
953 // Ignore the return value (declarations are statements). | 947 // Ignore the return value (declarations are statements). |
954 return; | 948 return; |
955 } | 949 } |
956 | 950 |
(...skipping 685 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1642 JumpTarget exit; | 1636 JumpTarget exit; |
1643 | 1637 |
1644 // Get the object to enumerate over (converted to JSObject). | 1638 // Get the object to enumerate over (converted to JSObject). |
1645 LoadAndSpill(node->enumerable()); | 1639 LoadAndSpill(node->enumerable()); |
1646 | 1640 |
1647 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 1641 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
1648 // to the specification. 12.6.4 mandates a call to ToObject. | 1642 // to the specification. 12.6.4 mandates a call to ToObject. |
1649 frame_->EmitPop(rax); | 1643 frame_->EmitPop(rax); |
1650 | 1644 |
1651 // rax: value to be iterated over | 1645 // rax: value to be iterated over |
1652 __ Cmp(rax, Factory::undefined_value()); | 1646 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
1653 exit.Branch(equal); | 1647 exit.Branch(equal); |
1654 __ Cmp(rax, Factory::null_value()); | 1648 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
1655 exit.Branch(equal); | 1649 exit.Branch(equal); |
1656 | 1650 |
1657 // Stack layout in body: | 1651 // Stack layout in body: |
1658 // [iteration counter (smi)] <- slot 0 | 1652 // [iteration counter (smi)] <- slot 0 |
1659 // [length of array] <- slot 1 | 1653 // [length of array] <- slot 1 |
1660 // [FixedArray] <- slot 2 | 1654 // [FixedArray] <- slot 2 |
1661 // [Map or 0] <- slot 3 | 1655 // [Map or 0] <- slot 3 |
1662 // [Object] <- slot 4 | 1656 // [Object] <- slot 4 |
1663 | 1657 |
1664 // Check if enumerable is already a JSObject | 1658 // Check if enumerable is already a JSObject |
(...skipping 15 matching lines...) Expand all Loading... |
1680 | 1674 |
1681 frame_->EmitPush(rax); // push the Object (slot 4) for the runtime call | 1675 frame_->EmitPush(rax); // push the Object (slot 4) for the runtime call |
1682 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 1676 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
1683 | 1677 |
1684 // If we got a Map, we can do a fast modification check. | 1678 // If we got a Map, we can do a fast modification check. |
1685 // Otherwise, we got a FixedArray, and we have to do a slow check. | 1679 // Otherwise, we got a FixedArray, and we have to do a slow check. |
1686 // rax: map or fixed array (result from call to | 1680 // rax: map or fixed array (result from call to |
1687 // Runtime::kGetPropertyNamesFast) | 1681 // Runtime::kGetPropertyNamesFast) |
1688 __ movq(rdx, rax); | 1682 __ movq(rdx, rax); |
1689 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); | 1683 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); |
1690 __ Cmp(rcx, Factory::meta_map()); | 1684 __ CompareRoot(rcx, Heap::kMetaMapRootIndex); |
1691 fixed_array.Branch(not_equal); | 1685 fixed_array.Branch(not_equal); |
1692 | 1686 |
1693 // Get enum cache | 1687 // Get enum cache |
1694 // rax: map (result from call to Runtime::kGetPropertyNamesFast) | 1688 // rax: map (result from call to Runtime::kGetPropertyNamesFast) |
1695 __ movq(rcx, rax); | 1689 __ movq(rcx, rax); |
1696 __ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset)); | 1690 __ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset)); |
1697 // Get the bridge array held in the enumeration index field. | 1691 // Get the bridge array held in the enumeration index field. |
1698 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); | 1692 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); |
1699 // Get the cache from the bridge array. | 1693 // Get the cache from the bridge array. |
1700 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 1694 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1749 __ cmpq(rcx, rdx); | 1743 __ cmpq(rcx, rdx); |
1750 end_del_check.Branch(equal); | 1744 end_del_check.Branch(equal); |
1751 | 1745 |
1752 // Convert the entry to a string (or null if it isn't a property anymore). | 1746 // Convert the entry to a string (or null if it isn't a property anymore). |
1753 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable | 1747 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable |
1754 frame_->EmitPush(rbx); // push entry | 1748 frame_->EmitPush(rbx); // push entry |
1755 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); | 1749 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); |
1756 __ movq(rbx, rax); | 1750 __ movq(rbx, rax); |
1757 | 1751 |
1758 // If the property has been removed while iterating, we just skip it. | 1752 // If the property has been removed while iterating, we just skip it. |
1759 __ Cmp(rbx, Factory::null_value()); | 1753 __ CompareRoot(rbx, Heap::kNullValueRootIndex); |
1760 node->continue_target()->Branch(equal); | 1754 node->continue_target()->Branch(equal); |
1761 | 1755 |
1762 end_del_check.Bind(); | 1756 end_del_check.Bind(); |
1763 // Store the entry in the 'each' expression and take another spin in the | 1757 // Store the entry in the 'each' expression and take another spin in the |
1764 // loop. rdx: i'th entry of the enum cache (or string there of) | 1758 // loop. rdx: i'th entry of the enum cache (or string there of) |
1765 frame_->EmitPush(rbx); | 1759 frame_->EmitPush(rbx); |
1766 { Reference each(this, node->each()); | 1760 { Reference each(this, node->each()); |
1767 // Loading a reference may leave the frame in an unspilled state. | 1761 // Loading a reference may leave the frame in an unspilled state. |
1768 frame_->SpillAll(); | 1762 frame_->SpillAll(); |
1769 if (!each.is_illegal()) { | 1763 if (!each.is_illegal()) { |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2024 // chain and set the state on the frame to FALLING. | 2018 // chain and set the state on the frame to FALLING. |
2025 if (has_valid_frame()) { | 2019 if (has_valid_frame()) { |
2026 // The next handler address is on top of the frame. | 2020 // The next handler address is on top of the frame. |
2027 ASSERT(StackHandlerConstants::kNextOffset == 0); | 2021 ASSERT(StackHandlerConstants::kNextOffset == 0); |
2028 __ movq(kScratchRegister, handler_address); | 2022 __ movq(kScratchRegister, handler_address); |
2029 frame_->EmitPop(Operand(kScratchRegister, 0)); | 2023 frame_->EmitPop(Operand(kScratchRegister, 0)); |
2030 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2024 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
2031 | 2025 |
2032 // Fake a top of stack value (unneeded when FALLING) and set the | 2026 // Fake a top of stack value (unneeded when FALLING) and set the |
2033 // state in ecx, then jump around the unlink blocks if any. | 2027 // state in ecx, then jump around the unlink blocks if any. |
2034 __ movq(kScratchRegister, | 2028 frame_->EmitPush(Heap::kUndefinedValueRootIndex); |
2035 Factory::undefined_value(), | |
2036 RelocInfo::EMBEDDED_OBJECT); | |
2037 frame_->EmitPush(kScratchRegister); | |
2038 __ movq(rcx, Immediate(Smi::FromInt(FALLING))); | 2029 __ movq(rcx, Immediate(Smi::FromInt(FALLING))); |
2039 if (nof_unlinks > 0) { | 2030 if (nof_unlinks > 0) { |
2040 finally_block.Jump(); | 2031 finally_block.Jump(); |
2041 } | 2032 } |
2042 } | 2033 } |
2043 | 2034 |
2044 // Generate code to unlink and set the state for the (formerly) | 2035 // Generate code to unlink and set the state for the (formerly) |
2045 // shadowing targets that have been jumped to. | 2036 // shadowing targets that have been jumped to. |
2046 for (int i = 0; i < shadows.length(); i++) { | 2037 for (int i = 0; i < shadows.length(); i++) { |
2047 if (shadows[i]->is_linked()) { | 2038 if (shadows[i]->is_linked()) { |
(...skipping 24 matching lines...) Expand all Loading... |
2072 __ movq(kScratchRegister, handler_address); | 2063 __ movq(kScratchRegister, handler_address); |
2073 frame_->EmitPop(Operand(kScratchRegister, 0)); | 2064 frame_->EmitPop(Operand(kScratchRegister, 0)); |
2074 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2065 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
2075 | 2066 |
2076 if (i == kReturnShadowIndex) { | 2067 if (i == kReturnShadowIndex) { |
2077 // If this target shadowed the function return, materialize | 2068 // If this target shadowed the function return, materialize |
2078 // the return value on the stack. | 2069 // the return value on the stack. |
2079 frame_->EmitPush(rax); | 2070 frame_->EmitPush(rax); |
2080 } else { | 2071 } else { |
2081 // Fake TOS for targets that shadowed breaks and continues. | 2072 // Fake TOS for targets that shadowed breaks and continues. |
2082 __ movq(kScratchRegister, | 2073 frame_->EmitPush(Heap::kUndefinedValueRootIndex); |
2083 Factory::undefined_value(), | |
2084 RelocInfo::EMBEDDED_OBJECT); | |
2085 frame_->EmitPush(kScratchRegister); | |
2086 } | 2074 } |
2087 __ movq(rcx, Immediate(Smi::FromInt(JUMPING + i))); | 2075 __ movq(rcx, Immediate(Smi::FromInt(JUMPING + i))); |
2088 if (--nof_unlinks > 0) { | 2076 if (--nof_unlinks > 0) { |
2089 // If this is not the last unlink block, jump around the next. | 2077 // If this is not the last unlink block, jump around the next. |
2090 finally_block.Jump(); | 2078 finally_block.Jump(); |
2091 } | 2079 } |
2092 } | 2080 } |
2093 } | 2081 } |
2094 | 2082 |
2095 // --- Finally block --- | 2083 // --- Finally block --- |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2317 Result boilerplate = allocator_->Allocate(); | 2305 Result boilerplate = allocator_->Allocate(); |
2318 ASSERT(boilerplate.is_valid()); | 2306 ASSERT(boilerplate.is_valid()); |
2319 int literal_offset = | 2307 int literal_offset = |
2320 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 2308 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
2321 __ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); | 2309 __ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); |
2322 | 2310 |
2323 // Check whether we need to materialize the RegExp object. If so, | 2311 // Check whether we need to materialize the RegExp object. If so, |
2324 // jump to the deferred code passing the literals array. | 2312 // jump to the deferred code passing the literals array. |
2325 DeferredRegExpLiteral* deferred = | 2313 DeferredRegExpLiteral* deferred = |
2326 new DeferredRegExpLiteral(boilerplate.reg(), literals.reg(), node); | 2314 new DeferredRegExpLiteral(boilerplate.reg(), literals.reg(), node); |
2327 __ Cmp(boilerplate.reg(), Factory::undefined_value()); | 2315 __ CompareRoot(boilerplate.reg(), Heap::kUndefinedValueRootIndex); |
2328 deferred->Branch(equal); | 2316 deferred->Branch(equal); |
2329 deferred->BindExit(); | 2317 deferred->BindExit(); |
2330 literals.Unuse(); | 2318 literals.Unuse(); |
2331 | 2319 |
2332 // Push the boilerplate object. | 2320 // Push the boilerplate object. |
2333 frame_->Push(&boilerplate); | 2321 frame_->Push(&boilerplate); |
2334 } | 2322 } |
2335 | 2323 |
2336 | 2324 |
2337 // Materialize the object literal 'node' in the literals array | 2325 // Materialize the object literal 'node' in the literals array |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2388 Result boilerplate = allocator_->Allocate(); | 2376 Result boilerplate = allocator_->Allocate(); |
2389 ASSERT(boilerplate.is_valid()); | 2377 ASSERT(boilerplate.is_valid()); |
2390 int literal_offset = | 2378 int literal_offset = |
2391 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 2379 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
2392 __ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); | 2380 __ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); |
2393 | 2381 |
2394 // Check whether we need to materialize the object literal boilerplate. | 2382 // Check whether we need to materialize the object literal boilerplate. |
2395 // If so, jump to the deferred code passing the literals array. | 2383 // If so, jump to the deferred code passing the literals array. |
2396 DeferredObjectLiteral* deferred = | 2384 DeferredObjectLiteral* deferred = |
2397 new DeferredObjectLiteral(boilerplate.reg(), literals.reg(), node); | 2385 new DeferredObjectLiteral(boilerplate.reg(), literals.reg(), node); |
2398 __ Cmp(boilerplate.reg(), Factory::undefined_value()); | 2386 __ CompareRoot(boilerplate.reg(), Heap::kUndefinedValueRootIndex); |
2399 deferred->Branch(equal); | 2387 deferred->Branch(equal); |
2400 deferred->BindExit(); | 2388 deferred->BindExit(); |
2401 literals.Unuse(); | 2389 literals.Unuse(); |
2402 | 2390 |
2403 // Push the boilerplate object. | 2391 // Push the boilerplate object. |
2404 frame_->Push(&boilerplate); | 2392 frame_->Push(&boilerplate); |
2405 // Clone the boilerplate object. | 2393 // Clone the boilerplate object. |
2406 Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate; | 2394 Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate; |
2407 if (node->depth() == 1) { | 2395 if (node->depth() == 1) { |
2408 clone_function_id = Runtime::kCloneShallowLiteralBoilerplate; | 2396 clone_function_id = Runtime::kCloneShallowLiteralBoilerplate; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2521 Result boilerplate = allocator_->Allocate(); | 2509 Result boilerplate = allocator_->Allocate(); |
2522 ASSERT(boilerplate.is_valid()); | 2510 ASSERT(boilerplate.is_valid()); |
2523 int literal_offset = | 2511 int literal_offset = |
2524 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; | 2512 FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
2525 __ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); | 2513 __ movq(boilerplate.reg(), FieldOperand(literals.reg(), literal_offset)); |
2526 | 2514 |
2527 // Check whether we need to materialize the object literal boilerplate. | 2515 // Check whether we need to materialize the object literal boilerplate. |
2528 // If so, jump to the deferred code passing the literals array. | 2516 // If so, jump to the deferred code passing the literals array. |
2529 DeferredArrayLiteral* deferred = | 2517 DeferredArrayLiteral* deferred = |
2530 new DeferredArrayLiteral(boilerplate.reg(), literals.reg(), node); | 2518 new DeferredArrayLiteral(boilerplate.reg(), literals.reg(), node); |
2531 __ Cmp(boilerplate.reg(), Factory::undefined_value()); | 2519 __ CompareRoot(boilerplate.reg(), Heap::kUndefinedValueRootIndex); |
2532 deferred->Branch(equal); | 2520 deferred->Branch(equal); |
2533 deferred->BindExit(); | 2521 deferred->BindExit(); |
2534 literals.Unuse(); | 2522 literals.Unuse(); |
2535 | 2523 |
2536 // Push the resulting array literal boilerplate on the stack. | 2524 // Push the resulting array literal boilerplate on the stack. |
2537 frame_->Push(&boilerplate); | 2525 frame_->Push(&boilerplate); |
2538 // Clone the boilerplate object. | 2526 // Clone the boilerplate object. |
2539 Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate; | 2527 Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate; |
2540 if (node->depth() == 1) { | 2528 if (node->depth() == 1) { |
2541 clone_function_id = Runtime::kCloneShallowLiteralBoilerplate; | 2529 clone_function_id = Runtime::kCloneShallowLiteralBoilerplate; |
(...skipping 937 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3479 // Load the operand and move it to a register. | 3467 // Load the operand and move it to a register. |
3480 LoadTypeofExpression(operation->expression()); | 3468 LoadTypeofExpression(operation->expression()); |
3481 Result answer = frame_->Pop(); | 3469 Result answer = frame_->Pop(); |
3482 answer.ToRegister(); | 3470 answer.ToRegister(); |
3483 | 3471 |
3484 if (check->Equals(Heap::number_symbol())) { | 3472 if (check->Equals(Heap::number_symbol())) { |
3485 __ testl(answer.reg(), Immediate(kSmiTagMask)); | 3473 __ testl(answer.reg(), Immediate(kSmiTagMask)); |
3486 destination()->true_target()->Branch(zero); | 3474 destination()->true_target()->Branch(zero); |
3487 frame_->Spill(answer.reg()); | 3475 frame_->Spill(answer.reg()); |
3488 __ movq(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 3476 __ movq(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
3489 __ Cmp(answer.reg(), Factory::heap_number_map()); | 3477 __ CompareRoot(answer.reg(), Heap::kHeapNumberMapRootIndex); |
3490 answer.Unuse(); | 3478 answer.Unuse(); |
3491 destination()->Split(equal); | 3479 destination()->Split(equal); |
3492 | 3480 |
3493 } else if (check->Equals(Heap::string_symbol())) { | 3481 } else if (check->Equals(Heap::string_symbol())) { |
3494 __ testl(answer.reg(), Immediate(kSmiTagMask)); | 3482 __ testl(answer.reg(), Immediate(kSmiTagMask)); |
3495 destination()->false_target()->Branch(zero); | 3483 destination()->false_target()->Branch(zero); |
3496 | 3484 |
3497 // It can be an undetectable string object. | 3485 // It can be an undetectable string object. |
3498 __ movq(kScratchRegister, | 3486 __ movq(kScratchRegister, |
3499 FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 3487 FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
3500 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), | 3488 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
3501 Immediate(1 << Map::kIsUndetectable)); | 3489 Immediate(1 << Map::kIsUndetectable)); |
3502 destination()->false_target()->Branch(not_zero); | 3490 destination()->false_target()->Branch(not_zero); |
3503 __ CmpInstanceType(kScratchRegister, FIRST_NONSTRING_TYPE); | 3491 __ CmpInstanceType(kScratchRegister, FIRST_NONSTRING_TYPE); |
3504 answer.Unuse(); | 3492 answer.Unuse(); |
3505 destination()->Split(below); // Unsigned byte comparison needed. | 3493 destination()->Split(below); // Unsigned byte comparison needed. |
3506 | 3494 |
3507 } else if (check->Equals(Heap::boolean_symbol())) { | 3495 } else if (check->Equals(Heap::boolean_symbol())) { |
3508 __ Cmp(answer.reg(), Factory::true_value()); | 3496 __ CompareRoot(answer.reg(), Heap::kTrueValueRootIndex); |
3509 destination()->true_target()->Branch(equal); | 3497 destination()->true_target()->Branch(equal); |
3510 __ Cmp(answer.reg(), Factory::false_value()); | 3498 __ CompareRoot(answer.reg(), Heap::kFalseValueRootIndex); |
3511 answer.Unuse(); | 3499 answer.Unuse(); |
3512 destination()->Split(equal); | 3500 destination()->Split(equal); |
3513 | 3501 |
3514 } else if (check->Equals(Heap::undefined_symbol())) { | 3502 } else if (check->Equals(Heap::undefined_symbol())) { |
3515 __ Cmp(answer.reg(), Factory::undefined_value()); | 3503 __ CompareRoot(answer.reg(), Heap::kUndefinedValueRootIndex); |
3516 destination()->true_target()->Branch(equal); | 3504 destination()->true_target()->Branch(equal); |
3517 | 3505 |
3518 __ testl(answer.reg(), Immediate(kSmiTagMask)); | 3506 __ testl(answer.reg(), Immediate(kSmiTagMask)); |
3519 destination()->false_target()->Branch(zero); | 3507 destination()->false_target()->Branch(zero); |
3520 | 3508 |
3521 // It can be an undetectable object. | 3509 // It can be an undetectable object. |
3522 __ movq(kScratchRegister, | 3510 __ movq(kScratchRegister, |
3523 FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 3511 FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
3524 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), | 3512 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
3525 Immediate(1 << Map::kIsUndetectable)); | 3513 Immediate(1 << Map::kIsUndetectable)); |
3526 answer.Unuse(); | 3514 answer.Unuse(); |
3527 destination()->Split(not_zero); | 3515 destination()->Split(not_zero); |
3528 | 3516 |
3529 } else if (check->Equals(Heap::function_symbol())) { | 3517 } else if (check->Equals(Heap::function_symbol())) { |
3530 __ testl(answer.reg(), Immediate(kSmiTagMask)); | 3518 __ testl(answer.reg(), Immediate(kSmiTagMask)); |
3531 destination()->false_target()->Branch(zero); | 3519 destination()->false_target()->Branch(zero); |
3532 frame_->Spill(answer.reg()); | 3520 frame_->Spill(answer.reg()); |
3533 __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); | 3521 __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); |
3534 answer.Unuse(); | 3522 answer.Unuse(); |
3535 destination()->Split(equal); | 3523 destination()->Split(equal); |
3536 | 3524 |
3537 } else if (check->Equals(Heap::object_symbol())) { | 3525 } else if (check->Equals(Heap::object_symbol())) { |
3538 __ testl(answer.reg(), Immediate(kSmiTagMask)); | 3526 __ testl(answer.reg(), Immediate(kSmiTagMask)); |
3539 destination()->false_target()->Branch(zero); | 3527 destination()->false_target()->Branch(zero); |
3540 __ Cmp(answer.reg(), Factory::null_value()); | 3528 __ CompareRoot(answer.reg(), Heap::kNullValueRootIndex); |
3541 destination()->true_target()->Branch(equal); | 3529 destination()->true_target()->Branch(equal); |
3542 | 3530 |
3543 // It can be an undetectable object. | 3531 // It can be an undetectable object. |
3544 __ movq(kScratchRegister, | 3532 __ movq(kScratchRegister, |
3545 FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 3533 FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
3546 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), | 3534 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
3547 Immediate(1 << Map::kIsUndetectable)); | 3535 Immediate(1 << Map::kIsUndetectable)); |
3548 destination()->false_target()->Branch(not_zero); | 3536 destination()->false_target()->Branch(not_zero); |
3549 __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE); | 3537 __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE); |
3550 destination()->false_target()->Branch(below); | 3538 destination()->false_target()->Branch(below); |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3824 __ bind(&a_cons_string); | 3812 __ bind(&a_cons_string); |
3825 // Get the first of the two strings. Both sliced and cons strings | 3813 // Get the first of the two strings. Both sliced and cons strings |
3826 // store their source string at the same offset. | 3814 // store their source string at the same offset. |
3827 ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset); | 3815 ASSERT(SlicedString::kBufferOffset == ConsString::kFirstOffset); |
3828 __ movq(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset)); | 3816 __ movq(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset)); |
3829 __ jmp(&try_again_with_new_string); | 3817 __ jmp(&try_again_with_new_string); |
3830 | 3818 |
3831 __ bind(&slow_case); | 3819 __ bind(&slow_case); |
3832 // Move the undefined value into the result register, which will | 3820 // Move the undefined value into the result register, which will |
3833 // trigger the slow case. | 3821 // trigger the slow case. |
3834 __ Move(temp.reg(), Factory::undefined_value()); | 3822 __ LoadRoot(temp.reg(), Heap::kUndefinedValueRootIndex); |
3835 | 3823 |
3836 __ bind(&end); | 3824 __ bind(&end); |
3837 frame_->Push(&temp); | 3825 frame_->Push(&temp); |
3838 } | 3826 } |
3839 | 3827 |
3840 | 3828 |
3841 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3829 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
3842 ASSERT(args->length() == 1); | 3830 ASSERT(args->length() == 1); |
3843 Load(args->at(0)); | 3831 Load(args->at(0)); |
3844 Result value = frame_->Pop(); | 3832 Result value = frame_->Pop(); |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4267 // 'false_target'/'true_target' as appropriate. | 4255 // 'false_target'/'true_target' as appropriate. |
4268 void CodeGenerator::ToBoolean(ControlDestination* dest) { | 4256 void CodeGenerator::ToBoolean(ControlDestination* dest) { |
4269 Comment cmnt(masm_, "[ ToBoolean"); | 4257 Comment cmnt(masm_, "[ ToBoolean"); |
4270 | 4258 |
4271 // The value to convert should be popped from the frame. | 4259 // The value to convert should be popped from the frame. |
4272 Result value = frame_->Pop(); | 4260 Result value = frame_->Pop(); |
4273 value.ToRegister(); | 4261 value.ToRegister(); |
4274 // Fast case checks. | 4262 // Fast case checks. |
4275 | 4263 |
4276 // 'false' => false. | 4264 // 'false' => false. |
4277 __ Cmp(value.reg(), Factory::false_value()); | 4265 __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex); |
4278 dest->false_target()->Branch(equal); | 4266 dest->false_target()->Branch(equal); |
4279 | 4267 |
4280 // 'true' => true. | 4268 // 'true' => true. |
4281 __ Cmp(value.reg(), Factory::true_value()); | 4269 __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex); |
4282 dest->true_target()->Branch(equal); | 4270 dest->true_target()->Branch(equal); |
4283 | 4271 |
4284 // 'undefined' => false. | 4272 // 'undefined' => false. |
4285 __ Cmp(value.reg(), Factory::undefined_value()); | 4273 __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex); |
4286 dest->false_target()->Branch(equal); | 4274 dest->false_target()->Branch(equal); |
4287 | 4275 |
4288 // Smi => false iff zero. | 4276 // Smi => false iff zero. |
4289 ASSERT(kSmiTag == 0); | 4277 ASSERT(kSmiTag == 0); |
4290 __ testl(value.reg(), value.reg()); | 4278 __ testl(value.reg(), value.reg()); |
4291 dest->false_target()->Branch(zero); | 4279 dest->false_target()->Branch(zero); |
4292 __ testl(value.reg(), Immediate(kSmiTagMask)); | 4280 __ testl(value.reg(), Immediate(kSmiTagMask)); |
4293 dest->true_target()->Branch(zero); | 4281 dest->true_target()->Branch(zero); |
4294 | 4282 |
4295 // Call the stub for all other cases. | 4283 // Call the stub for all other cases. |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4494 // Allocate a fresh register to use as a temp in | 4482 // Allocate a fresh register to use as a temp in |
4495 // ContextSlotOperandCheckExtensions and to hold the result | 4483 // ContextSlotOperandCheckExtensions and to hold the result |
4496 // value. | 4484 // value. |
4497 value = allocator_->Allocate(); | 4485 value = allocator_->Allocate(); |
4498 ASSERT(value.is_valid()); | 4486 ASSERT(value.is_valid()); |
4499 __ movq(value.reg(), | 4487 __ movq(value.reg(), |
4500 ContextSlotOperandCheckExtensions(potential_slot, | 4488 ContextSlotOperandCheckExtensions(potential_slot, |
4501 value, | 4489 value, |
4502 &slow)); | 4490 &slow)); |
4503 if (potential_slot->var()->mode() == Variable::CONST) { | 4491 if (potential_slot->var()->mode() == Variable::CONST) { |
4504 __ Cmp(value.reg(), Factory::the_hole_value()); | 4492 __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); |
4505 done.Branch(not_equal, &value); | 4493 done.Branch(not_equal, &value); |
4506 __ movq(value.reg(), Factory::undefined_value(), | 4494 __ LoadRoot(value.reg(), Heap::kUndefinedValueRootIndex); |
4507 RelocInfo::EMBEDDED_OBJECT); | |
4508 } | 4495 } |
4509 // There is always control flow to slow from | 4496 // There is always control flow to slow from |
4510 // ContextSlotOperandCheckExtensions so we have to jump around | 4497 // ContextSlotOperandCheckExtensions so we have to jump around |
4511 // it. | 4498 // it. |
4512 done.Jump(&value); | 4499 done.Jump(&value); |
4513 } | 4500 } |
4514 } | 4501 } |
4515 | 4502 |
4516 slow.Bind(); | 4503 slow.Bind(); |
4517 // A runtime call is inevitable. We eagerly sync frame elements | 4504 // A runtime call is inevitable. We eagerly sync frame elements |
(...skipping 17 matching lines...) Expand all Loading... |
4535 // Const slots may contain 'the hole' value (the constant hasn't been | 4522 // Const slots may contain 'the hole' value (the constant hasn't been |
4536 // initialized yet) which needs to be converted into the 'undefined' | 4523 // initialized yet) which needs to be converted into the 'undefined' |
4537 // value. | 4524 // value. |
4538 // | 4525 // |
4539 // We currently spill the virtual frame because constants use the | 4526 // We currently spill the virtual frame because constants use the |
4540 // potentially unsafe direct-frame access of SlotOperand. | 4527 // potentially unsafe direct-frame access of SlotOperand. |
4541 VirtualFrame::SpilledScope spilled_scope; | 4528 VirtualFrame::SpilledScope spilled_scope; |
4542 Comment cmnt(masm_, "[ Load const"); | 4529 Comment cmnt(masm_, "[ Load const"); |
4543 JumpTarget exit; | 4530 JumpTarget exit; |
4544 __ movq(rcx, SlotOperand(slot, rcx)); | 4531 __ movq(rcx, SlotOperand(slot, rcx)); |
4545 __ Cmp(rcx, Factory::the_hole_value()); | 4532 __ CompareRoot(rcx, Heap::kTheHoleValueRootIndex); |
4546 exit.Branch(not_equal); | 4533 exit.Branch(not_equal); |
4547 __ movq(rcx, Factory::undefined_value(), RelocInfo::EMBEDDED_OBJECT); | 4534 __ LoadRoot(rcx, Heap::kUndefinedValueRootIndex); |
4548 exit.Bind(); | 4535 exit.Bind(); |
4549 frame_->EmitPush(rcx); | 4536 frame_->EmitPush(rcx); |
4550 | 4537 |
4551 } else if (slot->type() == Slot::PARAMETER) { | 4538 } else if (slot->type() == Slot::PARAMETER) { |
4552 frame_->PushParameterAt(slot->index()); | 4539 frame_->PushParameterAt(slot->index()); |
4553 | 4540 |
4554 } else if (slot->type() == Slot::LOCAL) { | 4541 } else if (slot->type() == Slot::LOCAL) { |
4555 frame_->PushLocalAt(slot->index()); | 4542 frame_->PushLocalAt(slot->index()); |
4556 | 4543 |
4557 } else { | 4544 } else { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4591 } else { | 4578 } else { |
4592 frame_->Push(&value); | 4579 frame_->Push(&value); |
4593 } | 4580 } |
4594 return; | 4581 return; |
4595 } | 4582 } |
4596 | 4583 |
4597 // The loaded value is in a register. If it is the sentinel that | 4584 // The loaded value is in a register. If it is the sentinel that |
4598 // indicates that we haven't loaded the arguments object yet, we | 4585 // indicates that we haven't loaded the arguments object yet, we |
4599 // need to do it now. | 4586 // need to do it now. |
4600 JumpTarget exit; | 4587 JumpTarget exit; |
4601 __ Cmp(value.reg(), Factory::the_hole_value()); | 4588 __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); |
4602 frame_->Push(&value); | 4589 frame_->Push(&value); |
4603 exit.Branch(not_equal); | 4590 exit.Branch(not_equal); |
4604 Result arguments = StoreArgumentsObject(false); | 4591 Result arguments = StoreArgumentsObject(false); |
4605 frame_->SetElementAt(0, &arguments); | 4592 frame_->SetElementAt(0, &arguments); |
4606 exit.Bind(); | 4593 exit.Bind(); |
4607 } | 4594 } |
4608 | 4595 |
4609 | 4596 |
4610 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 4597 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
4611 if (slot->type() == Slot::LOOKUP) { | 4598 if (slot->type() == Slot::LOOKUP) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4652 // Only the first const initialization must be executed (the slot | 4639 // Only the first const initialization must be executed (the slot |
4653 // still contains 'the hole' value). When the assignment is executed, | 4640 // still contains 'the hole' value). When the assignment is executed, |
4654 // the code is identical to a normal store (see below). | 4641 // the code is identical to a normal store (see below). |
4655 // | 4642 // |
4656 // We spill the frame in the code below because the direct-frame | 4643 // We spill the frame in the code below because the direct-frame |
4657 // access of SlotOperand is potentially unsafe with an unspilled | 4644 // access of SlotOperand is potentially unsafe with an unspilled |
4658 // frame. | 4645 // frame. |
4659 VirtualFrame::SpilledScope spilled_scope; | 4646 VirtualFrame::SpilledScope spilled_scope; |
4660 Comment cmnt(masm_, "[ Init const"); | 4647 Comment cmnt(masm_, "[ Init const"); |
4661 __ movq(rcx, SlotOperand(slot, rcx)); | 4648 __ movq(rcx, SlotOperand(slot, rcx)); |
4662 __ Cmp(rcx, Factory::the_hole_value()); | 4649 __ CompareRoot(rcx, Heap::kTheHoleValueRootIndex); |
4663 exit.Branch(not_equal); | 4650 exit.Branch(not_equal); |
4664 } | 4651 } |
4665 | 4652 |
4666 // We must execute the store. Storing a variable must keep the (new) | 4653 // We must execute the store. Storing a variable must keep the (new) |
4667 // value on the stack. This is necessary for compiling assignment | 4654 // value on the stack. This is necessary for compiling assignment |
4668 // expressions. | 4655 // expressions. |
4669 // | 4656 // |
4670 // Note: We will reach here even with slot->var()->mode() == | 4657 // Note: We will reach here even with slot->var()->mode() == |
4671 // Variable::CONST because of const declarations which will initialize | 4658 // Variable::CONST because of const declarations which will initialize |
4672 // consts to 'the hole' value and by doing so, end up calling this code. | 4659 // consts to 'the hole' value and by doing so, end up calling this code. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4736 } | 4723 } |
4737 | 4724 |
4738 if (s->is_eval_scope()) { | 4725 if (s->is_eval_scope()) { |
4739 // Loop up the context chain. There is no frame effect so it is | 4726 // Loop up the context chain. There is no frame effect so it is |
4740 // safe to use raw labels here. | 4727 // safe to use raw labels here. |
4741 Label next, fast; | 4728 Label next, fast; |
4742 if (!context.is(tmp.reg())) { | 4729 if (!context.is(tmp.reg())) { |
4743 __ movq(tmp.reg(), context); | 4730 __ movq(tmp.reg(), context); |
4744 } | 4731 } |
4745 // Load map for comparison into register, outside loop. | 4732 // Load map for comparison into register, outside loop. |
4746 __ Move(kScratchRegister, Factory::global_context_map()); | 4733 __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex); |
4747 __ bind(&next); | 4734 __ bind(&next); |
4748 // Terminate at global context. | 4735 // Terminate at global context. |
4749 __ cmpq(kScratchRegister, FieldOperand(tmp.reg(), HeapObject::kMapOffset)); | 4736 __ cmpq(kScratchRegister, FieldOperand(tmp.reg(), HeapObject::kMapOffset)); |
4750 __ j(equal, &fast); | 4737 __ j(equal, &fast); |
4751 // Check that extension is NULL. | 4738 // Check that extension is NULL. |
4752 __ cmpq(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0)); | 4739 __ cmpq(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0)); |
4753 slow->Branch(not_equal); | 4740 slow->Branch(not_equal); |
4754 // Load next context in chain. | 4741 // Load next context in chain. |
4755 __ movq(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); | 4742 __ movq(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); |
4756 __ movq(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); | 4743 __ movq(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4840 // We have to skip storing into the arguments slot if it has | 4827 // We have to skip storing into the arguments slot if it has |
4841 // already been written to. This can happen if the a function | 4828 // already been written to. This can happen if the a function |
4842 // has a local variable named 'arguments'. | 4829 // has a local variable named 'arguments'. |
4843 LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | 4830 LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); |
4844 Result arguments = frame_->Pop(); | 4831 Result arguments = frame_->Pop(); |
4845 if (arguments.is_constant()) { | 4832 if (arguments.is_constant()) { |
4846 // We have to skip updating the arguments object if it has | 4833 // We have to skip updating the arguments object if it has |
4847 // been assigned a proper value. | 4834 // been assigned a proper value. |
4848 skip_arguments = !arguments.handle()->IsTheHole(); | 4835 skip_arguments = !arguments.handle()->IsTheHole(); |
4849 } else { | 4836 } else { |
4850 __ Cmp(arguments.reg(), Factory::the_hole_value()); | 4837 __ CompareRoot(arguments.reg(), Heap::kTheHoleValueRootIndex); |
4851 arguments.Unuse(); | 4838 arguments.Unuse(); |
4852 done.Branch(not_equal); | 4839 done.Branch(not_equal); |
4853 } | 4840 } |
4854 } | 4841 } |
4855 if (!skip_arguments) { | 4842 if (!skip_arguments) { |
4856 arguments_ref.SetValue(NOT_CONST_INIT); | 4843 arguments_ref.SetValue(NOT_CONST_INIT); |
4857 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | 4844 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); |
4858 } | 4845 } |
4859 shadow_ref.SetValue(NOT_CONST_INIT); | 4846 shadow_ref.SetValue(NOT_CONST_INIT); |
4860 } | 4847 } |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4978 } else if (cc == equal && | 4965 } else if (cc == equal && |
4979 (left_side_constant_null || right_side_constant_null)) { | 4966 (left_side_constant_null || right_side_constant_null)) { |
4980 // To make null checks efficient, we check if either the left side or | 4967 // To make null checks efficient, we check if either the left side or |
4981 // the right side is the constant 'null'. | 4968 // the right side is the constant 'null'. |
4982 // If so, we optimize the code by inlining a null check instead of | 4969 // If so, we optimize the code by inlining a null check instead of |
4983 // calling the (very) general runtime routine for checking equality. | 4970 // calling the (very) general runtime routine for checking equality. |
4984 Result operand = left_side_constant_null ? right_side : left_side; | 4971 Result operand = left_side_constant_null ? right_side : left_side; |
4985 right_side.Unuse(); | 4972 right_side.Unuse(); |
4986 left_side.Unuse(); | 4973 left_side.Unuse(); |
4987 operand.ToRegister(); | 4974 operand.ToRegister(); |
4988 __ Cmp(operand.reg(), Factory::null_value()); | 4975 __ CompareRoot(operand.reg(), Heap::kNullValueRootIndex); |
4989 if (strict) { | 4976 if (strict) { |
4990 operand.Unuse(); | 4977 operand.Unuse(); |
4991 dest->Split(equal); | 4978 dest->Split(equal); |
4992 } else { | 4979 } else { |
4993 // The 'null' value is only equal to 'undefined' if using non-strict | 4980 // The 'null' value is only equal to 'undefined' if using non-strict |
4994 // comparisons. | 4981 // comparisons. |
4995 dest->true_target()->Branch(equal); | 4982 dest->true_target()->Branch(equal); |
4996 __ Cmp(operand.reg(), Factory::undefined_value()); | 4983 __ CompareRoot(operand.reg(), Heap::kUndefinedValueRootIndex); |
4997 dest->true_target()->Branch(equal); | 4984 dest->true_target()->Branch(equal); |
4998 __ testl(operand.reg(), Immediate(kSmiTagMask)); | 4985 __ testl(operand.reg(), Immediate(kSmiTagMask)); |
4999 dest->false_target()->Branch(equal); | 4986 dest->false_target()->Branch(equal); |
5000 | 4987 |
5001 // It can be an undetectable object. | 4988 // It can be an undetectable object. |
5002 // Use a scratch register in preference to spilling operand.reg(). | 4989 // Use a scratch register in preference to spilling operand.reg(). |
5003 Result temp = allocator()->Allocate(); | 4990 Result temp = allocator()->Allocate(); |
5004 ASSERT(temp.is_valid()); | 4991 ASSERT(temp.is_valid()); |
5005 __ movq(temp.reg(), | 4992 __ movq(temp.reg(), |
5006 FieldOperand(operand.reg(), HeapObject::kMapOffset)); | 4993 FieldOperand(operand.reg(), HeapObject::kMapOffset)); |
(...skipping 1099 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6106 // one is rax, the we can reuse that one because the value | 6093 // one is rax, the we can reuse that one because the value |
6107 // coming from the deferred code will be in rax. | 6094 // coming from the deferred code will be in rax. |
6108 Result value = index; | 6095 Result value = index; |
6109 __ movq(value.reg(), | 6096 __ movq(value.reg(), |
6110 Operand(elements.reg(), | 6097 Operand(elements.reg(), |
6111 index.reg(), | 6098 index.reg(), |
6112 times_pointer_size, | 6099 times_pointer_size, |
6113 FixedArray::kHeaderSize - kHeapObjectTag)); | 6100 FixedArray::kHeaderSize - kHeapObjectTag)); |
6114 elements.Unuse(); | 6101 elements.Unuse(); |
6115 index.Unuse(); | 6102 index.Unuse(); |
6116 __ Cmp(value.reg(), Factory::the_hole_value()); | 6103 __ CompareRoot(value.reg(), Heap::kTheHoleValueRootIndex); |
6117 deferred->Branch(equal); | 6104 deferred->Branch(equal); |
6118 __ IncrementCounter(&Counters::keyed_load_inline, 1); | 6105 __ IncrementCounter(&Counters::keyed_load_inline, 1); |
6119 | 6106 |
6120 deferred->BindExit(); | 6107 deferred->BindExit(); |
6121 // Restore the receiver and key to the frame and push the | 6108 // Restore the receiver and key to the frame and push the |
6122 // result on top of it. | 6109 // result on top of it. |
6123 cgen_->frame()->Push(&receiver); | 6110 cgen_->frame()->Push(&receiver); |
6124 cgen_->frame()->Push(&key); | 6111 cgen_->frame()->Push(&key); |
6125 cgen_->frame()->Push(&value); | 6112 cgen_->frame()->Push(&value); |
6126 | 6113 |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6315 UNREACHABLE(); | 6302 UNREACHABLE(); |
6316 } | 6303 } |
6317 } | 6304 } |
6318 | 6305 |
6319 | 6306 |
6320 void ToBooleanStub::Generate(MacroAssembler* masm) { | 6307 void ToBooleanStub::Generate(MacroAssembler* masm) { |
6321 Label false_result, true_result, not_string; | 6308 Label false_result, true_result, not_string; |
6322 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 6309 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
6323 | 6310 |
6324 // 'null' => false. | 6311 // 'null' => false. |
6325 __ Cmp(rax, Factory::null_value()); | 6312 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
6326 __ j(equal, &false_result); | 6313 __ j(equal, &false_result); |
6327 | 6314 |
6328 // Get the map and type of the heap object. | 6315 // Get the map and type of the heap object. |
6329 // We don't use CmpObjectType because we manipulate the type field. | 6316 // We don't use CmpObjectType because we manipulate the type field. |
6330 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 6317 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
6331 __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); | 6318 __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); |
6332 | 6319 |
6333 // Undetectable => false. | 6320 // Undetectable => false. |
6334 __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset)); | 6321 __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset)); |
6335 __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); | 6322 __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); |
(...skipping 10 matching lines...) Expand all Loading... |
6346 __ cmpq(rcx, Immediate(kShortStringTag)); | 6333 __ cmpq(rcx, Immediate(kShortStringTag)); |
6347 __ j(not_equal, &true_result); // Empty string is always short. | 6334 __ j(not_equal, &true_result); // Empty string is always short. |
6348 __ movl(rdx, FieldOperand(rax, String::kLengthOffset)); | 6335 __ movl(rdx, FieldOperand(rax, String::kLengthOffset)); |
6349 __ shr(rdx, Immediate(String::kShortLengthShift)); | 6336 __ shr(rdx, Immediate(String::kShortLengthShift)); |
6350 __ j(zero, &false_result); | 6337 __ j(zero, &false_result); |
6351 __ jmp(&true_result); | 6338 __ jmp(&true_result); |
6352 | 6339 |
6353 __ bind(¬_string); | 6340 __ bind(¬_string); |
6354 // HeapNumber => false iff +0, -0, or NaN. | 6341 // HeapNumber => false iff +0, -0, or NaN. |
6355 // These three cases set C3 when compared to zero in the FPU. | 6342 // These three cases set C3 when compared to zero in the FPU. |
6356 __ Cmp(rdx, Factory::heap_number_map()); | 6343 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); |
6357 __ j(not_equal, &true_result); | 6344 __ j(not_equal, &true_result); |
6358 // TODO(x64): Don't use fp stack, use MMX registers? | 6345 // TODO(x64): Don't use fp stack, use MMX registers? |
6359 __ fldz(); // Load zero onto fp stack | 6346 __ fldz(); // Load zero onto fp stack |
6360 // Load heap-number double value onto fp stack | 6347 // Load heap-number double value onto fp stack |
6361 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 6348 __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
6362 __ fucompp(); // Compare and pop both values. | 6349 __ fucompp(); // Compare and pop both values. |
6363 __ movq(kScratchRegister, rax); | 6350 __ movq(kScratchRegister, rax); |
6364 __ fnstsw_ax(); // Store fp status word in ax, no checking for exceptions. | 6351 __ fnstsw_ax(); // Store fp status word in ax, no checking for exceptions. |
6365 __ testl(rax, Immediate(0x4000)); // Test FP condition flag C3, bit 16. | 6352 __ testl(rax, Immediate(0x4000)); // Test FP condition flag C3, bit 16. |
6366 __ movq(rax, kScratchRegister); | 6353 __ movq(rax, kScratchRegister); |
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6759 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); | 6746 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); |
6760 __ j(below, &slow); | 6747 __ j(below, &slow); |
6761 __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); | 6748 __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); |
6762 __ j(above, &slow); | 6749 __ j(above, &slow); |
6763 | 6750 |
6764 // Register mapping: rax is object map and rbx is function prototype. | 6751 // Register mapping: rax is object map and rbx is function prototype. |
6765 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); | 6752 __ movq(rcx, FieldOperand(rax, Map::kPrototypeOffset)); |
6766 | 6753 |
6767 // Loop through the prototype chain looking for the function prototype. | 6754 // Loop through the prototype chain looking for the function prototype. |
6768 Label loop, is_instance, is_not_instance; | 6755 Label loop, is_instance, is_not_instance; |
6769 __ Move(kScratchRegister, Factory::null_value()); | 6756 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); |
6770 __ bind(&loop); | 6757 __ bind(&loop); |
6771 __ cmpq(rcx, rbx); | 6758 __ cmpq(rcx, rbx); |
6772 __ j(equal, &is_instance); | 6759 __ j(equal, &is_instance); |
6773 __ cmpq(rcx, kScratchRegister); | 6760 __ cmpq(rcx, kScratchRegister); |
6774 __ j(equal, &is_not_instance); | 6761 __ j(equal, &is_not_instance); |
6775 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); | 6762 __ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); |
6776 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); | 6763 __ movq(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); |
6777 __ jmp(&loop); | 6764 __ jmp(&loop); |
6778 | 6765 |
6779 __ bind(&is_instance); | 6766 __ bind(&is_instance); |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7013 // Retrieve the pending exception and clear the variable. | 7000 // Retrieve the pending exception and clear the variable. |
7014 ExternalReference pending_exception_address(Top::k_pending_exception_address); | 7001 ExternalReference pending_exception_address(Top::k_pending_exception_address); |
7015 __ movq(kScratchRegister, pending_exception_address); | 7002 __ movq(kScratchRegister, pending_exception_address); |
7016 __ movq(rax, Operand(kScratchRegister, 0)); | 7003 __ movq(rax, Operand(kScratchRegister, 0)); |
7017 __ movq(rdx, ExternalReference::the_hole_value_location()); | 7004 __ movq(rdx, ExternalReference::the_hole_value_location()); |
7018 __ movq(rdx, Operand(rdx, 0)); | 7005 __ movq(rdx, Operand(rdx, 0)); |
7019 __ movq(Operand(kScratchRegister, 0), rdx); | 7006 __ movq(Operand(kScratchRegister, 0), rdx); |
7020 | 7007 |
7021 // Special handling of termination exceptions which are uncatchable | 7008 // Special handling of termination exceptions which are uncatchable |
7022 // by javascript code. | 7009 // by javascript code. |
7023 __ Cmp(rax, Factory::termination_exception()); | 7010 __ CompareRoot(rax, Heap::kTerminationExceptionRootIndex); |
7024 __ j(equal, throw_termination_exception); | 7011 __ j(equal, throw_termination_exception); |
7025 | 7012 |
7026 // Handle normal exception. | 7013 // Handle normal exception. |
7027 __ jmp(throw_normal_exception); | 7014 __ jmp(throw_normal_exception); |
7028 | 7015 |
7029 // Retry. | 7016 // Retry. |
7030 __ bind(&retry); | 7017 __ bind(&retry); |
7031 } | 7018 } |
7032 | 7019 |
7033 | 7020 |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7327 // Allocate heap number in new space. | 7314 // Allocate heap number in new space. |
7328 __ AllocateObjectInNewSpace(HeapNumber::kSize, | 7315 __ AllocateObjectInNewSpace(HeapNumber::kSize, |
7329 result, | 7316 result, |
7330 scratch, | 7317 scratch, |
7331 no_reg, | 7318 no_reg, |
7332 need_gc, | 7319 need_gc, |
7333 false); | 7320 false); |
7334 | 7321 |
7335 // Set the map and tag the result. | 7322 // Set the map and tag the result. |
7336 __ addq(result, Immediate(kHeapObjectTag)); | 7323 __ addq(result, Immediate(kHeapObjectTag)); |
7337 __ movq(kScratchRegister, | 7324 __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex); |
7338 Factory::heap_number_map(), | |
7339 RelocInfo::EMBEDDED_OBJECT); | |
7340 __ movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); | 7325 __ movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister); |
7341 } | 7326 } |
7342 | 7327 |
7343 | 7328 |
7344 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 7329 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
7345 Register number) { | 7330 Register number) { |
7346 Label load_smi, done; | 7331 Label load_smi, done; |
7347 | 7332 |
7348 __ testl(number, Immediate(kSmiTagMask)); | 7333 __ testl(number, Immediate(kSmiTagMask)); |
7349 __ j(zero, &load_smi); | 7334 __ j(zero, &load_smi); |
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7879 int CompareStub::MinorKey() { | 7864 int CompareStub::MinorKey() { |
7880 // Encode the two parameters in a unique 16 bit value. | 7865 // Encode the two parameters in a unique 16 bit value. |
7881 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); | 7866 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); |
7882 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); | 7867 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); |
7883 } | 7868 } |
7884 | 7869 |
7885 | 7870 |
7886 #undef __ | 7871 #undef __ |
7887 | 7872 |
7888 } } // namespace v8::internal | 7873 } } // namespace v8::internal |
OLD | NEW |