| OLD | NEW |
| 1 // Copyright 2010 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 LoadFromSlotCheckForArguments(variable->AsSlot(), INSIDE_TYPEOF); | 608 LoadFromSlotCheckForArguments(variable->AsSlot(), INSIDE_TYPEOF); |
| 609 } else { | 609 } else { |
| 610 // Anything else can be handled normally. | 610 // Anything else can be handled normally. |
| 611 Load(expr); | 611 Load(expr); |
| 612 } | 612 } |
| 613 } | 613 } |
| 614 | 614 |
| 615 | 615 |
| 616 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { | 616 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { |
| 617 if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; | 617 if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; |
| 618 ASSERT(scope()->arguments_shadow() != NULL); | 618 |
| 619 // In strict mode there is no need for shadow arguments. |
| 620 ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode()); |
| 619 // We don't want to do lazy arguments allocation for functions that | 621 // We don't want to do lazy arguments allocation for functions that |
| 620 // have heap-allocated contexts, because it interfers with the | 622 // have heap-allocated contexts, because it interfers with the |
| 621 // uninitialized const tracking in the context objects. | 623 // uninitialized const tracking in the context objects. |
| 622 return (scope()->num_heap_slots() > 0) | 624 return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode()) |
| 623 ? EAGER_ARGUMENTS_ALLOCATION | 625 ? EAGER_ARGUMENTS_ALLOCATION |
| 624 : LAZY_ARGUMENTS_ALLOCATION; | 626 : LAZY_ARGUMENTS_ALLOCATION; |
| 625 } | 627 } |
| 626 | 628 |
| 627 | 629 |
| 628 Result CodeGenerator::StoreArgumentsObject(bool initial) { | 630 Result CodeGenerator::StoreArgumentsObject(bool initial) { |
| 629 ArgumentsAllocationMode mode = ArgumentsMode(); | 631 ArgumentsAllocationMode mode = ArgumentsMode(); |
| 630 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); | 632 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); |
| 631 | 633 |
| 632 Comment cmnt(masm_, "[ store arguments object"); | 634 Comment cmnt(masm_, "[ store arguments object"); |
| 633 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { | 635 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { |
| 634 // When using lazy arguments allocation, we store the arguments marker value | 636 // When using lazy arguments allocation, we store the arguments marker value |
| 635 // as a sentinel indicating that the arguments object hasn't been | 637 // as a sentinel indicating that the arguments object hasn't been |
| 636 // allocated yet. | 638 // allocated yet. |
| 637 frame_->Push(Factory::arguments_marker()); | 639 frame_->Push(Factory::arguments_marker()); |
| 638 } else { | 640 } else { |
| 639 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 641 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 640 frame_->PushFunction(); | 642 frame_->PushFunction(); |
| 641 frame_->PushReceiverSlotAddress(); | 643 frame_->PushReceiverSlotAddress(); |
| 642 frame_->Push(Smi::FromInt(scope()->num_parameters())); | 644 frame_->Push(Smi::FromInt(scope()->num_parameters())); |
| 643 Result result = frame_->CallStub(&stub, 3); | 645 Result result = frame_->CallStub(&stub, 3); |
| 644 frame_->Push(&result); | 646 frame_->Push(&result); |
| 645 } | 647 } |
| 646 | 648 |
| 647 Variable* arguments = scope()->arguments(); | 649 Variable* arguments = scope()->arguments(); |
| 648 Variable* shadow = scope()->arguments_shadow(); | 650 Variable* shadow = scope()->arguments_shadow(); |
| 649 ASSERT(arguments != NULL && arguments->AsSlot() != NULL); | 651 ASSERT(arguments != NULL && arguments->AsSlot() != NULL); |
| 650 ASSERT(shadow != NULL && shadow->AsSlot() != NULL); | 652 ASSERT((shadow != NULL && shadow->AsSlot() != NULL) || |
| 653 scope()->is_strict_mode()); |
| 654 |
| 651 JumpTarget done; | 655 JumpTarget done; |
| 652 bool skip_arguments = false; | 656 bool skip_arguments = false; |
| 653 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { | 657 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { |
| 654 // We have to skip storing into the arguments slot if it has | 658 // We have to skip storing into the arguments slot if it has |
| 655 // already been written to. This can happen if the a function | 659 // already been written to. This can happen if the a function |
| 656 // has a local variable named 'arguments'. | 660 // has a local variable named 'arguments'. |
| 657 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF); | 661 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF); |
| 658 Result probe = frame_->Pop(); | 662 Result probe = frame_->Pop(); |
| 659 if (probe.is_constant()) { | 663 if (probe.is_constant()) { |
| 660 // We have to skip updating the arguments object if it has | 664 // We have to skip updating the arguments object if it has |
| 661 // been assigned a proper value. | 665 // been assigned a proper value. |
| 662 skip_arguments = !probe.handle()->IsArgumentsMarker(); | 666 skip_arguments = !probe.handle()->IsArgumentsMarker(); |
| 663 } else { | 667 } else { |
| 664 __ CompareRoot(probe.reg(), Heap::kArgumentsMarkerRootIndex); | 668 __ CompareRoot(probe.reg(), Heap::kArgumentsMarkerRootIndex); |
| 665 probe.Unuse(); | 669 probe.Unuse(); |
| 666 done.Branch(not_equal); | 670 done.Branch(not_equal); |
| 667 } | 671 } |
| 668 } | 672 } |
| 669 if (!skip_arguments) { | 673 if (!skip_arguments) { |
| 670 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); | 674 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); |
| 671 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | 675 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); |
| 672 } | 676 } |
| 673 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); | 677 if (shadow != NULL) { |
| 678 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); |
| 679 } |
| 674 return frame_->Pop(); | 680 return frame_->Pop(); |
| 675 } | 681 } |
| 676 | 682 |
| 677 //------------------------------------------------------------------------------ | 683 //------------------------------------------------------------------------------ |
| 678 // CodeGenerator implementation of variables, lookups, and stores. | 684 // CodeGenerator implementation of variables, lookups, and stores. |
| 679 | 685 |
| 680 Reference::Reference(CodeGenerator* cgen, | 686 Reference::Reference(CodeGenerator* cgen, |
| 681 Expression* expression, | 687 Expression* expression, |
| 682 bool persist_after_get) | 688 bool persist_after_get) |
| 683 : cgen_(cgen), | 689 : cgen_(cgen), |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 // The value to convert should be popped from the frame. | 763 // The value to convert should be popped from the frame. |
| 758 Result value = frame_->Pop(); | 764 Result value = frame_->Pop(); |
| 759 value.ToRegister(); | 765 value.ToRegister(); |
| 760 | 766 |
| 761 if (value.is_number()) { | 767 if (value.is_number()) { |
| 762 // Fast case if TypeInfo indicates only numbers. | 768 // Fast case if TypeInfo indicates only numbers. |
| 763 if (FLAG_debug_code) { | 769 if (FLAG_debug_code) { |
| 764 __ AbortIfNotNumber(value.reg()); | 770 __ AbortIfNotNumber(value.reg()); |
| 765 } | 771 } |
| 766 // Smi => false iff zero. | 772 // Smi => false iff zero. |
| 767 __ SmiCompare(value.reg(), Smi::FromInt(0)); | 773 __ Cmp(value.reg(), Smi::FromInt(0)); |
| 768 if (value.is_smi()) { | 774 if (value.is_smi()) { |
| 769 value.Unuse(); | 775 value.Unuse(); |
| 770 dest->Split(not_zero); | 776 dest->Split(not_zero); |
| 771 } else { | 777 } else { |
| 772 dest->false_target()->Branch(equal); | 778 dest->false_target()->Branch(equal); |
| 773 Condition is_smi = masm_->CheckSmi(value.reg()); | 779 Condition is_smi = masm_->CheckSmi(value.reg()); |
| 774 dest->true_target()->Branch(is_smi); | 780 dest->true_target()->Branch(is_smi); |
| 775 __ xorpd(xmm0, xmm0); | 781 __ xorpd(xmm0, xmm0); |
| 776 __ ucomisd(xmm0, FieldOperand(value.reg(), HeapNumber::kValueOffset)); | 782 __ ucomisd(xmm0, FieldOperand(value.reg(), HeapNumber::kValueOffset)); |
| 777 value.Unuse(); | 783 value.Unuse(); |
| 778 dest->Split(not_zero); | 784 dest->Split(not_zero); |
| 779 } | 785 } |
| 780 } else { | 786 } else { |
| 781 // Fast case checks. | 787 // Fast case checks. |
| 782 // 'false' => false. | 788 // 'false' => false. |
| 783 __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex); | 789 __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex); |
| 784 dest->false_target()->Branch(equal); | 790 dest->false_target()->Branch(equal); |
| 785 | 791 |
| 786 // 'true' => true. | 792 // 'true' => true. |
| 787 __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex); | 793 __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex); |
| 788 dest->true_target()->Branch(equal); | 794 dest->true_target()->Branch(equal); |
| 789 | 795 |
| 790 // 'undefined' => false. | 796 // 'undefined' => false. |
| 791 __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex); | 797 __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex); |
| 792 dest->false_target()->Branch(equal); | 798 dest->false_target()->Branch(equal); |
| 793 | 799 |
| 794 // Smi => false iff zero. | 800 // Smi => false iff zero. |
| 795 __ SmiCompare(value.reg(), Smi::FromInt(0)); | 801 __ Cmp(value.reg(), Smi::FromInt(0)); |
| 796 dest->false_target()->Branch(equal); | 802 dest->false_target()->Branch(equal); |
| 797 Condition is_smi = masm_->CheckSmi(value.reg()); | 803 Condition is_smi = masm_->CheckSmi(value.reg()); |
| 798 dest->true_target()->Branch(is_smi); | 804 dest->true_target()->Branch(is_smi); |
| 799 | 805 |
| 800 // Call the stub for all other cases. | 806 // Call the stub for all other cases. |
| 801 frame_->Push(&value); // Undo the Pop() from above. | 807 frame_->Push(&value); // Undo the Pop() from above. |
| 802 ToBooleanStub stub; | 808 ToBooleanStub stub; |
| 803 Result temp = frame_->CallStub(&stub, 1); | 809 Result temp = frame_->CallStub(&stub, 1); |
| 804 // Convert the result to a condition code. | 810 // Convert the result to a condition code. |
| 805 __ testq(temp.reg(), temp.reg()); | 811 __ testq(temp.reg(), temp.reg()); |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1027 operands_type); | 1033 operands_type); |
| 1028 answer = GenerateGenericBinaryOpStubCall(&stub, &left, &right); | 1034 answer = GenerateGenericBinaryOpStubCall(&stub, &left, &right); |
| 1029 } else if (right_is_smi_constant) { | 1035 } else if (right_is_smi_constant) { |
| 1030 answer = ConstantSmiBinaryOperation(expr, &left, right.handle(), | 1036 answer = ConstantSmiBinaryOperation(expr, &left, right.handle(), |
| 1031 false, overwrite_mode); | 1037 false, overwrite_mode); |
| 1032 } else if (left_is_smi_constant) { | 1038 } else if (left_is_smi_constant) { |
| 1033 answer = ConstantSmiBinaryOperation(expr, &right, left.handle(), | 1039 answer = ConstantSmiBinaryOperation(expr, &right, left.handle(), |
| 1034 true, overwrite_mode); | 1040 true, overwrite_mode); |
| 1035 } else { | 1041 } else { |
| 1036 // Set the flags based on the operation, type and loop nesting level. | 1042 // Set the flags based on the operation, type and loop nesting level. |
| 1037 // Bit operations always assume they likely operate on Smis. Still only | 1043 // Bit operations always assume they likely operate on smis. Still only |
| 1038 // generate the inline Smi check code if this operation is part of a loop. | 1044 // generate the inline Smi check code if this operation is part of a loop. |
| 1039 // For all other operations only inline the Smi check code for likely smis | 1045 // For all other operations only inline the Smi check code for likely smis |
| 1040 // if the operation is part of a loop. | 1046 // if the operation is part of a loop. |
| 1041 if (loop_nesting() > 0 && | 1047 if (loop_nesting() > 0 && |
| 1042 (Token::IsBitOp(op) || | 1048 (Token::IsBitOp(op) || |
| 1043 operands_type.IsInteger32() || | 1049 operands_type.IsInteger32() || |
| 1044 expr->type()->IsLikelySmi())) { | 1050 expr->type()->IsLikelySmi())) { |
| 1045 answer = LikelySmiBinaryOperation(expr, &left, &right, overwrite_mode); | 1051 answer = LikelySmiBinaryOperation(expr, &left, &right, overwrite_mode); |
| 1046 } else { | 1052 } else { |
| 1047 GenericBinaryOpStub stub(op, | 1053 GenericBinaryOpStub stub(op, |
| (...skipping 1051 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2099 is_string.Bind(&left_side); | 2105 is_string.Bind(&left_side); |
| 2100 // left_side is a sequential ASCII string. | 2106 // left_side is a sequential ASCII string. |
| 2101 ASSERT(left_side.reg().is(left_reg)); | 2107 ASSERT(left_side.reg().is(left_reg)); |
| 2102 right_side = Result(right_val); | 2108 right_side = Result(right_val); |
| 2103 Result temp2 = allocator_->Allocate(); | 2109 Result temp2 = allocator_->Allocate(); |
| 2104 ASSERT(temp2.is_valid()); | 2110 ASSERT(temp2.is_valid()); |
| 2105 // Test string equality and comparison. | 2111 // Test string equality and comparison. |
| 2106 if (cc == equal) { | 2112 if (cc == equal) { |
| 2107 Label comparison_done; | 2113 Label comparison_done; |
| 2108 __ SmiCompare(FieldOperand(left_side.reg(), String::kLengthOffset), | 2114 __ SmiCompare(FieldOperand(left_side.reg(), String::kLengthOffset), |
| 2109 Smi::FromInt(1)); | 2115 Smi::FromInt(1)); |
| 2110 __ j(not_equal, &comparison_done); | 2116 __ j(not_equal, &comparison_done); |
| 2111 uint8_t char_value = | 2117 uint8_t char_value = |
| 2112 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); | 2118 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); |
| 2113 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), | 2119 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), |
| 2114 Immediate(char_value)); | 2120 Immediate(char_value)); |
| 2115 __ bind(&comparison_done); | 2121 __ bind(&comparison_done); |
| 2116 } else { | 2122 } else { |
| 2117 __ movq(temp2.reg(), | 2123 __ movq(temp2.reg(), |
| 2118 FieldOperand(left_side.reg(), String::kLengthOffset)); | 2124 FieldOperand(left_side.reg(), String::kLengthOffset)); |
| 2119 __ SmiSubConstant(temp2.reg(), temp2.reg(), Smi::FromInt(1)); | 2125 __ SmiSubConstant(temp2.reg(), temp2.reg(), Smi::FromInt(1)); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2285 // Since one side is a constant Smi, conversion order does not matter. | 2291 // Since one side is a constant Smi, conversion order does not matter. |
| 2286 if (left_side_constant_smi) { | 2292 if (left_side_constant_smi) { |
| 2287 Result* temp = left_side; | 2293 Result* temp = left_side; |
| 2288 left_side = right_side; | 2294 left_side = right_side; |
| 2289 right_side = temp; | 2295 right_side = temp; |
| 2290 cc = ReverseCondition(cc); | 2296 cc = ReverseCondition(cc); |
| 2291 // This may re-introduce greater or less_equal as the value of cc. | 2297 // This may re-introduce greater or less_equal as the value of cc. |
| 2292 // CompareStub and the inline code both support all values of cc. | 2298 // CompareStub and the inline code both support all values of cc. |
| 2293 } | 2299 } |
| 2294 // Implement comparison against a constant Smi, inlining the case | 2300 // Implement comparison against a constant Smi, inlining the case |
| 2295 // where both sides are Smis. | 2301 // where both sides are smis. |
| 2296 left_side->ToRegister(); | 2302 left_side->ToRegister(); |
| 2297 Register left_reg = left_side->reg(); | 2303 Register left_reg = left_side->reg(); |
| 2298 Smi* constant_smi = Smi::cast(*right_side->handle()); | 2304 Smi* constant_smi = Smi::cast(*right_side->handle()); |
| 2299 | 2305 |
| 2300 if (left_side->is_smi()) { | 2306 if (left_side->is_smi()) { |
| 2301 if (FLAG_debug_code) { | 2307 if (FLAG_debug_code) { |
| 2302 __ AbortIfNotSmi(left_reg); | 2308 __ AbortIfNotSmi(left_reg); |
| 2303 } | 2309 } |
| 2304 // Test smi equality and comparison by signed int comparison. | 2310 // Test smi equality and comparison by signed int comparison. |
| 2305 // Both sides are smis, so we can use an Immediate. | |
| 2306 __ SmiCompare(left_reg, constant_smi); | 2311 __ SmiCompare(left_reg, constant_smi); |
| 2307 left_side->Unuse(); | 2312 left_side->Unuse(); |
| 2308 right_side->Unuse(); | 2313 right_side->Unuse(); |
| 2309 dest->Split(cc); | 2314 dest->Split(cc); |
| 2310 } else { | 2315 } else { |
| 2311 // Only the case where the left side could possibly be a non-smi is left. | 2316 // Only the case where the left side could possibly be a non-smi is left. |
| 2312 JumpTarget is_smi; | 2317 JumpTarget is_smi; |
| 2313 if (cc == equal) { | 2318 if (cc == equal) { |
| 2314 // We can do the equality comparison before the smi check. | 2319 // We can do the equality comparison before the smi check. |
| 2315 __ SmiCompare(left_reg, constant_smi); | 2320 __ Cmp(left_reg, constant_smi); |
| 2316 dest->true_target()->Branch(equal); | 2321 dest->true_target()->Branch(equal); |
| 2317 Condition left_is_smi = masm_->CheckSmi(left_reg); | 2322 Condition left_is_smi = masm_->CheckSmi(left_reg); |
| 2318 dest->false_target()->Branch(left_is_smi); | 2323 dest->false_target()->Branch(left_is_smi); |
| 2319 } else { | 2324 } else { |
| 2320 // Do the smi check, then the comparison. | 2325 // Do the smi check, then the comparison. |
| 2321 Condition left_is_smi = masm_->CheckSmi(left_reg); | 2326 Condition left_is_smi = masm_->CheckSmi(left_reg); |
| 2322 is_smi.Branch(left_is_smi, left_side, right_side); | 2327 is_smi.Branch(left_is_smi, left_side, right_side); |
| 2323 } | 2328 } |
| 2324 | 2329 |
| 2325 // Jump or fall through to here if we are comparing a non-smi to a | 2330 // Jump or fall through to here if we are comparing a non-smi to a |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2566 __ movq(rdi, Operand(rsp, 2 * kPointerSize)); | 2571 __ movq(rdi, Operand(rsp, 2 * kPointerSize)); |
| 2567 is_smi = masm_->CheckSmi(rdi); | 2572 is_smi = masm_->CheckSmi(rdi); |
| 2568 __ j(is_smi, &build_args); | 2573 __ j(is_smi, &build_args); |
| 2569 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 2574 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| 2570 __ j(not_equal, &build_args); | 2575 __ j(not_equal, &build_args); |
| 2571 | 2576 |
| 2572 // Copy the arguments to this function possibly from the | 2577 // Copy the arguments to this function possibly from the |
| 2573 // adaptor frame below it. | 2578 // adaptor frame below it. |
| 2574 Label invoke, adapted; | 2579 Label invoke, adapted; |
| 2575 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2580 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2576 __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), | 2581 __ Cmp(Operand(rdx, StandardFrameConstants::kContextOffset), |
| 2577 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2582 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2578 __ j(equal, &adapted); | 2583 __ j(equal, &adapted); |
| 2579 | 2584 |
| 2580 // No arguments adaptor frame. Copy fixed number of arguments. | 2585 // No arguments adaptor frame. Copy fixed number of arguments. |
| 2581 __ Set(rax, scope()->num_parameters()); | 2586 __ Set(rax, scope()->num_parameters()); |
| 2582 for (int i = 0; i < scope()->num_parameters(); i++) { | 2587 for (int i = 0; i < scope()->num_parameters(); i++) { |
| 2583 __ push(frame_->ParameterAt(i)); | 2588 __ push(frame_->ParameterAt(i)); |
| 2584 } | 2589 } |
| 2585 __ jmp(&invoke); | 2590 __ jmp(&invoke); |
| 2586 | 2591 |
| 2587 // Arguments adaptor frame present. Copy arguments from there, but | 2592 // Arguments adaptor frame present. Copy arguments from there, but |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2744 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 2749 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 2745 // Call the runtime to declare the globals. The inevitable call | 2750 // Call the runtime to declare the globals. The inevitable call |
| 2746 // will sync frame elements to memory anyway, so we do it eagerly to | 2751 // will sync frame elements to memory anyway, so we do it eagerly to |
| 2747 // allow us to push the arguments directly into place. | 2752 // allow us to push the arguments directly into place. |
| 2748 frame_->SyncRange(0, frame_->element_count() - 1); | 2753 frame_->SyncRange(0, frame_->element_count() - 1); |
| 2749 | 2754 |
| 2750 __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT); | 2755 __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT); |
| 2751 frame_->EmitPush(rsi); // The context is the first argument. | 2756 frame_->EmitPush(rsi); // The context is the first argument. |
| 2752 frame_->EmitPush(kScratchRegister); | 2757 frame_->EmitPush(kScratchRegister); |
| 2753 frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0)); | 2758 frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0)); |
| 2754 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 2759 frame_->EmitPush(Smi::FromInt(strict_mode_flag())); |
| 2760 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 4); |
| 2755 // Return value is ignored. | 2761 // Return value is ignored. |
| 2756 } | 2762 } |
| 2757 | 2763 |
| 2758 | 2764 |
| 2759 void CodeGenerator::VisitDeclaration(Declaration* node) { | 2765 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 2760 Comment cmnt(masm_, "[ Declaration"); | 2766 Comment cmnt(masm_, "[ Declaration"); |
| 2761 Variable* var = node->proxy()->var(); | 2767 Variable* var = node->proxy()->var(); |
| 2762 ASSERT(var != NULL); // must have been resolved | 2768 ASSERT(var != NULL); // must have been resolved |
| 2763 Slot* slot = var->AsSlot(); | 2769 Slot* slot = var->AsSlot(); |
| 2764 | 2770 |
| (...skipping 1082 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3847 __ cmpq(rcx, rdx); | 3853 __ cmpq(rcx, rdx); |
| 3848 end_del_check.Branch(equal); | 3854 end_del_check.Branch(equal); |
| 3849 | 3855 |
| 3850 // Convert the entry to a string (or null if it isn't a property anymore). | 3856 // Convert the entry to a string (or null if it isn't a property anymore). |
| 3851 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable | 3857 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable |
| 3852 frame_->EmitPush(rbx); // push entry | 3858 frame_->EmitPush(rbx); // push entry |
| 3853 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); | 3859 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); |
| 3854 __ movq(rbx, rax); | 3860 __ movq(rbx, rax); |
| 3855 | 3861 |
| 3856 // If the property has been removed while iterating, we just skip it. | 3862 // If the property has been removed while iterating, we just skip it. |
| 3857 __ SmiCompare(rbx, Smi::FromInt(0)); | 3863 __ Cmp(rbx, Smi::FromInt(0)); |
| 3858 node->continue_target()->Branch(equal); | 3864 node->continue_target()->Branch(equal); |
| 3859 | 3865 |
| 3860 end_del_check.Bind(); | 3866 end_del_check.Bind(); |
| 3861 // Store the entry in the 'each' expression and take another spin in the | 3867 // Store the entry in the 'each' expression and take another spin in the |
| 3862 // loop. rdx: i'th entry of the enum cache (or string there of) | 3868 // loop. rdx: i'th entry of the enum cache (or string there of) |
| 3863 frame_->EmitPush(rbx); | 3869 frame_->EmitPush(rbx); |
| 3864 { Reference each(this, node->each()); | 3870 { Reference each(this, node->each()); |
| 3865 // Loading a reference may leave the frame in an unspilled state. | 3871 // Loading a reference may leave the frame in an unspilled state. |
| 3866 frame_->SpillAll(); | 3872 frame_->SpillAll(); |
| 3867 if (!each.is_illegal()) { | 3873 if (!each.is_illegal()) { |
| (...skipping 734 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4602 // context slot declaration, but we cannot initialize it at the same | 4608 // context slot declaration, but we cannot initialize it at the same |
| 4603 // time, because the const declaration may be at the end of the eval | 4609 // time, because the const declaration may be at the end of the eval |
| 4604 // code (sigh...) and the const variable may have been used before | 4610 // code (sigh...) and the const variable may have been used before |
| 4605 // (where its value is 'undefined'). Thus, we can only do the | 4611 // (where its value is 'undefined'). Thus, we can only do the |
| 4606 // initialization when we actually encounter the expression and when | 4612 // initialization when we actually encounter the expression and when |
| 4607 // the expression operands are defined and valid, and thus we need the | 4613 // the expression operands are defined and valid, and thus we need the |
| 4608 // split into 2 operations: declaration of the context slot followed | 4614 // split into 2 operations: declaration of the context slot followed |
| 4609 // by initialization. | 4615 // by initialization. |
| 4610 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 4616 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 4611 } else { | 4617 } else { |
| 4612 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); | 4618 frame_->Push(Smi::FromInt(strict_mode_flag())); |
| 4619 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 4); |
| 4613 } | 4620 } |
| 4614 // Storing a variable must keep the (new) value on the expression | 4621 // Storing a variable must keep the (new) value on the expression |
| 4615 // stack. This is necessary for compiling chained assignment | 4622 // stack. This is necessary for compiling chained assignment |
| 4616 // expressions. | 4623 // expressions. |
| 4617 frame_->Push(&value); | 4624 frame_->Push(&value); |
| 4618 } else { | 4625 } else { |
| 4619 ASSERT(!slot->var()->is_dynamic()); | 4626 ASSERT(!slot->var()->is_dynamic()); |
| 4620 | 4627 |
| 4621 JumpTarget exit; | 4628 JumpTarget exit; |
| 4622 if (init_state == CONST_INIT) { | 4629 if (init_state == CONST_INIT) { |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4915 break; | 4922 break; |
| 4916 } | 4923 } |
| 4917 // Fall through | 4924 // Fall through |
| 4918 } | 4925 } |
| 4919 case ObjectLiteral::Property::PROTOTYPE: { | 4926 case ObjectLiteral::Property::PROTOTYPE: { |
| 4920 // Duplicate the object as an argument to the runtime call. | 4927 // Duplicate the object as an argument to the runtime call. |
| 4921 frame_->Dup(); | 4928 frame_->Dup(); |
| 4922 Load(property->key()); | 4929 Load(property->key()); |
| 4923 Load(property->value()); | 4930 Load(property->value()); |
| 4924 if (property->emit_store()) { | 4931 if (property->emit_store()) { |
| 4932 frame_->Push(Smi::FromInt(NONE)); // PropertyAttributes |
| 4925 // Ignore the result. | 4933 // Ignore the result. |
| 4926 Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); | 4934 Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 4); |
| 4927 } else { | 4935 } else { |
| 4928 frame_->Drop(3); | 4936 frame_->Drop(3); |
| 4929 } | 4937 } |
| 4930 break; | 4938 break; |
| 4931 } | 4939 } |
| 4932 case ObjectLiteral::Property::SETTER: { | 4940 case ObjectLiteral::Property::SETTER: { |
| 4933 // Duplicate the object as an argument to the runtime call. | 4941 // Duplicate the object as an argument to the runtime call. |
| 4934 frame_->Dup(); | 4942 frame_->Dup(); |
| 4935 Load(property->key()); | 4943 Load(property->key()); |
| 4936 frame_->Push(Smi::FromInt(1)); | 4944 frame_->Push(Smi::FromInt(1)); |
| (...skipping 1257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6194 | 6202 |
| 6195 void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { | 6203 void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { |
| 6196 ASSERT(args->length() == 0); | 6204 ASSERT(args->length() == 0); |
| 6197 | 6205 |
| 6198 // Get the frame pointer for the calling frame. | 6206 // Get the frame pointer for the calling frame. |
| 6199 Result fp = allocator()->Allocate(); | 6207 Result fp = allocator()->Allocate(); |
| 6200 __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 6208 __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 6201 | 6209 |
| 6202 // Skip the arguments adaptor frame if it exists. | 6210 // Skip the arguments adaptor frame if it exists. |
| 6203 Label check_frame_marker; | 6211 Label check_frame_marker; |
| 6204 __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset), | 6212 __ Cmp(Operand(fp.reg(), StandardFrameConstants::kContextOffset), |
| 6205 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 6213 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 6206 __ j(not_equal, &check_frame_marker); | 6214 __ j(not_equal, &check_frame_marker); |
| 6207 __ movq(fp.reg(), Operand(fp.reg(), StandardFrameConstants::kCallerFPOffset)); | 6215 __ movq(fp.reg(), Operand(fp.reg(), StandardFrameConstants::kCallerFPOffset)); |
| 6208 | 6216 |
| 6209 // Check the marker in the calling frame. | 6217 // Check the marker in the calling frame. |
| 6210 __ bind(&check_frame_marker); | 6218 __ bind(&check_frame_marker); |
| 6211 __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset), | 6219 __ Cmp(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset), |
| 6212 Smi::FromInt(StackFrame::CONSTRUCT)); | 6220 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 6213 fp.Unuse(); | 6221 fp.Unuse(); |
| 6214 destination()->Split(equal); | 6222 destination()->Split(equal); |
| 6215 } | 6223 } |
| 6216 | 6224 |
| 6217 | 6225 |
| 6218 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 6226 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
| 6219 ASSERT(args->length() == 0); | 6227 ASSERT(args->length() == 0); |
| 6220 | 6228 |
| 6221 Result fp = allocator_->Allocate(); | 6229 Result fp = allocator_->Allocate(); |
| 6222 Result result = allocator_->Allocate(); | 6230 Result result = allocator_->Allocate(); |
| 6223 ASSERT(fp.is_valid() && result.is_valid()); | 6231 ASSERT(fp.is_valid() && result.is_valid()); |
| 6224 | 6232 |
| 6225 Label exit; | 6233 Label exit; |
| 6226 | 6234 |
| 6227 // Get the number of formal parameters. | 6235 // Get the number of formal parameters. |
| 6228 __ Move(result.reg(), Smi::FromInt(scope()->num_parameters())); | 6236 __ Move(result.reg(), Smi::FromInt(scope()->num_parameters())); |
| 6229 | 6237 |
| 6230 // Check if the calling frame is an arguments adaptor frame. | 6238 // Check if the calling frame is an arguments adaptor frame. |
| 6231 __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 6239 __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 6232 __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset), | 6240 __ Cmp(Operand(fp.reg(), StandardFrameConstants::kContextOffset), |
| 6233 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 6241 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 6234 __ j(not_equal, &exit); | 6242 __ j(not_equal, &exit); |
| 6235 | 6243 |
| 6236 // Arguments adaptor case: Read the arguments length from the | 6244 // Arguments adaptor case: Read the arguments length from the |
| 6237 // adaptor frame. | 6245 // adaptor frame. |
| 6238 __ movq(result.reg(), | 6246 __ movq(result.reg(), |
| 6239 Operand(fp.reg(), ArgumentsAdaptorFrameConstants::kLengthOffset)); | 6247 Operand(fp.reg(), ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 6240 | 6248 |
| 6241 __ bind(&exit); | 6249 __ bind(&exit); |
| 6242 result.set_type_info(TypeInfo::Smi()); | 6250 result.set_type_info(TypeInfo::Smi()); |
| 6243 if (FLAG_debug_code) { | 6251 if (FLAG_debug_code) { |
| (...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6782 frame_->Spill(index1.reg()); | 6790 frame_->Spill(index1.reg()); |
| 6783 frame_->Spill(index2.reg()); | 6791 frame_->Spill(index2.reg()); |
| 6784 | 6792 |
| 6785 DeferredSwapElements* deferred = new DeferredSwapElements(object.reg(), | 6793 DeferredSwapElements* deferred = new DeferredSwapElements(object.reg(), |
| 6786 index1.reg(), | 6794 index1.reg(), |
| 6787 index2.reg()); | 6795 index2.reg()); |
| 6788 | 6796 |
| 6789 // Fetch the map and check if array is in fast case. | 6797 // Fetch the map and check if array is in fast case. |
| 6790 // Check that object doesn't require security checks and | 6798 // Check that object doesn't require security checks and |
| 6791 // has no indexed interceptor. | 6799 // has no indexed interceptor. |
| 6792 __ CmpObjectType(object.reg(), FIRST_JS_OBJECT_TYPE, tmp1.reg()); | 6800 __ CmpObjectType(object.reg(), JS_ARRAY_TYPE, tmp1.reg()); |
| 6793 deferred->Branch(below); | 6801 deferred->Branch(not_equal); |
| 6794 __ testb(FieldOperand(tmp1.reg(), Map::kBitFieldOffset), | 6802 __ testb(FieldOperand(tmp1.reg(), Map::kBitFieldOffset), |
| 6795 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask)); | 6803 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask)); |
| 6796 deferred->Branch(not_zero); | 6804 deferred->Branch(not_zero); |
| 6797 | 6805 |
| 6798 // Check the object's elements are in fast case and writable. | 6806 // Check the object's elements are in fast case and writable. |
| 6799 __ movq(tmp1.reg(), FieldOperand(object.reg(), JSObject::kElementsOffset)); | 6807 __ movq(tmp1.reg(), FieldOperand(object.reg(), JSObject::kElementsOffset)); |
| 6800 __ CompareRoot(FieldOperand(tmp1.reg(), HeapObject::kMapOffset), | 6808 __ CompareRoot(FieldOperand(tmp1.reg(), HeapObject::kMapOffset), |
| 6801 Heap::kFixedArrayMapRootIndex); | 6809 Heap::kFixedArrayMapRootIndex); |
| 6802 deferred->Branch(not_equal); | 6810 deferred->Branch(not_equal); |
| 6803 | 6811 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 6825 FixedArray::kHeaderSize)); | 6833 FixedArray::kHeaderSize)); |
| 6826 | 6834 |
| 6827 // Swap elements. | 6835 // Swap elements. |
| 6828 __ movq(object.reg(), Operand(index1.reg(), 0)); | 6836 __ movq(object.reg(), Operand(index1.reg(), 0)); |
| 6829 __ movq(tmp2.reg(), Operand(index2.reg(), 0)); | 6837 __ movq(tmp2.reg(), Operand(index2.reg(), 0)); |
| 6830 __ movq(Operand(index2.reg(), 0), object.reg()); | 6838 __ movq(Operand(index2.reg(), 0), object.reg()); |
| 6831 __ movq(Operand(index1.reg(), 0), tmp2.reg()); | 6839 __ movq(Operand(index1.reg(), 0), tmp2.reg()); |
| 6832 | 6840 |
| 6833 Label done; | 6841 Label done; |
| 6834 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done); | 6842 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done); |
| 6835 // Possible optimization: do a check that both values are Smis | 6843 // Possible optimization: do a check that both values are smis |
| 6836 // (or them and test against Smi mask.) | 6844 // (or them and test against Smi mask.) |
| 6837 | 6845 |
| 6838 __ movq(tmp2.reg(), tmp1.reg()); | 6846 __ movq(tmp2.reg(), tmp1.reg()); |
| 6839 __ RecordWriteHelper(tmp1.reg(), index1.reg(), object.reg(), kDontSaveFPRegs); | 6847 __ RecordWriteHelper(tmp1.reg(), index1.reg(), object.reg(), kDontSaveFPRegs); |
| 6840 __ RecordWriteHelper(tmp2.reg(), index2.reg(), object.reg(), kDontSaveFPRegs); | 6848 __ RecordWriteHelper(tmp2.reg(), index2.reg(), object.reg(), kDontSaveFPRegs); |
| 6841 __ bind(&done); | 6849 __ bind(&done); |
| 6842 | 6850 |
| 6843 deferred->BindExit(); | 6851 deferred->BindExit(); |
| 6844 frame_->Push(Factory::undefined_value()); | 6852 frame_->Push(Factory::undefined_value()); |
| 6845 } | 6853 } |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7038 answer = frame()->CallRuntime(Runtime::kMath_pow_cfunction, 2); | 7046 answer = frame()->CallRuntime(Runtime::kMath_pow_cfunction, 2); |
| 7039 | 7047 |
| 7040 done.Bind(&answer); | 7048 done.Bind(&answer); |
| 7041 frame()->Push(&answer); | 7049 frame()->Push(&answer); |
| 7042 } | 7050 } |
| 7043 | 7051 |
| 7044 | 7052 |
| 7045 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { | 7053 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { |
| 7046 ASSERT_EQ(args->length(), 1); | 7054 ASSERT_EQ(args->length(), 1); |
| 7047 Load(args->at(0)); | 7055 Load(args->at(0)); |
| 7048 TranscendentalCacheStub stub(TranscendentalCache::SIN); | 7056 TranscendentalCacheStub stub(TranscendentalCache::SIN, |
| 7057 TranscendentalCacheStub::TAGGED); |
| 7049 Result result = frame_->CallStub(&stub, 1); | 7058 Result result = frame_->CallStub(&stub, 1); |
| 7050 frame_->Push(&result); | 7059 frame_->Push(&result); |
| 7051 } | 7060 } |
| 7052 | 7061 |
| 7053 | 7062 |
| 7054 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { | 7063 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { |
| 7055 ASSERT_EQ(args->length(), 1); | 7064 ASSERT_EQ(args->length(), 1); |
| 7056 Load(args->at(0)); | 7065 Load(args->at(0)); |
| 7057 TranscendentalCacheStub stub(TranscendentalCache::COS); | 7066 TranscendentalCacheStub stub(TranscendentalCache::COS, |
| 7067 TranscendentalCacheStub::TAGGED); |
| 7058 Result result = frame_->CallStub(&stub, 1); | 7068 Result result = frame_->CallStub(&stub, 1); |
| 7059 frame_->Push(&result); | 7069 frame_->Push(&result); |
| 7060 } | 7070 } |
| 7061 | 7071 |
| 7062 | 7072 |
| 7063 void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) { | 7073 void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) { |
| 7064 ASSERT_EQ(args->length(), 1); | 7074 ASSERT_EQ(args->length(), 1); |
| 7065 Load(args->at(0)); | 7075 Load(args->at(0)); |
| 7066 TranscendentalCacheStub stub(TranscendentalCache::LOG); | 7076 TranscendentalCacheStub stub(TranscendentalCache::LOG, |
| 7077 TranscendentalCacheStub::TAGGED); |
| 7067 Result result = frame_->CallStub(&stub, 1); | 7078 Result result = frame_->CallStub(&stub, 1); |
| 7068 frame_->Push(&result); | 7079 frame_->Push(&result); |
| 7069 } | 7080 } |
| 7070 | 7081 |
| 7071 | 7082 |
| 7072 // Generates the Math.sqrt method. Please note - this function assumes that | 7083 // Generates the Math.sqrt method. Please note - this function assumes that |
| 7073 // the callsite has executed ToNumber on the argument. | 7084 // the callsite has executed ToNumber on the argument. |
| 7074 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { | 7085 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
| 7075 ASSERT(args->length() == 1); | 7086 ASSERT(args->length() == 1); |
| 7076 Load(args->at(0)); | 7087 Load(args->at(0)); |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7247 Load(property->key()); | 7258 Load(property->key()); |
| 7248 frame_->Push(Smi::FromInt(strict_mode_flag())); | 7259 frame_->Push(Smi::FromInt(strict_mode_flag())); |
| 7249 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3); | 7260 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3); |
| 7250 frame_->Push(&answer); | 7261 frame_->Push(&answer); |
| 7251 return; | 7262 return; |
| 7252 } | 7263 } |
| 7253 | 7264 |
| 7254 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 7265 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
| 7255 if (variable != NULL) { | 7266 if (variable != NULL) { |
| 7256 // Delete of an unqualified identifier is disallowed in strict mode | 7267 // Delete of an unqualified identifier is disallowed in strict mode |
| 7257 // so this code can only be reached in non-strict mode. | 7268 // but "delete this" is. |
| 7258 ASSERT(strict_mode_flag() == kNonStrictMode); | 7269 ASSERT(strict_mode_flag() == kNonStrictMode || variable->is_this()); |
| 7259 Slot* slot = variable->AsSlot(); | 7270 Slot* slot = variable->AsSlot(); |
| 7260 if (variable->is_global()) { | 7271 if (variable->is_global()) { |
| 7261 LoadGlobal(); | 7272 LoadGlobal(); |
| 7262 frame_->Push(variable->name()); | 7273 frame_->Push(variable->name()); |
| 7263 frame_->Push(Smi::FromInt(kNonStrictMode)); | 7274 frame_->Push(Smi::FromInt(kNonStrictMode)); |
| 7264 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, | 7275 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, |
| 7265 CALL_FUNCTION, 3); | 7276 CALL_FUNCTION, 3); |
| 7266 frame_->Push(&answer); | 7277 frame_->Push(&answer); |
| 7267 return; | |
| 7268 | 7278 |
| 7269 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 7279 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 7270 // Call the runtime to delete from the context holding the named | 7280 // Call the runtime to delete from the context holding the named |
| 7271 // variable. Sync the virtual frame eagerly so we can push the | 7281 // variable. Sync the virtual frame eagerly so we can push the |
| 7272 // arguments directly into place. | 7282 // arguments directly into place. |
| 7273 frame_->SyncRange(0, frame_->element_count() - 1); | 7283 frame_->SyncRange(0, frame_->element_count() - 1); |
| 7274 frame_->EmitPush(rsi); | 7284 frame_->EmitPush(rsi); |
| 7275 frame_->EmitPush(variable->name()); | 7285 frame_->EmitPush(variable->name()); |
| 7276 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); | 7286 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); |
| 7277 frame_->Push(&answer); | 7287 frame_->Push(&answer); |
| 7278 return; | 7288 } else { |
| 7289 // Default: Result of deleting non-global, not dynamically |
| 7290 // introduced variables is false. |
| 7291 frame_->Push(Factory::false_value()); |
| 7279 } | 7292 } |
| 7280 | |
| 7281 // Default: Result of deleting non-global, not dynamically | |
| 7282 // introduced variables is false. | |
| 7283 frame_->Push(Factory::false_value()); | |
| 7284 | |
| 7285 } else { | 7293 } else { |
| 7286 // Default: Result of deleting expressions is true. | 7294 // Default: Result of deleting expressions is true. |
| 7287 Load(node->expression()); // may have side-effects | 7295 Load(node->expression()); // may have side-effects |
| 7288 frame_->SetElementAt(0, Factory::true_value()); | 7296 frame_->SetElementAt(0, Factory::true_value()); |
| 7289 } | 7297 } |
| 7290 | 7298 |
| 7291 } else if (op == Token::TYPEOF) { | 7299 } else if (op == Token::TYPEOF) { |
| 7292 // Special case for loading the typeof expression; see comment on | 7300 // Special case for loading the typeof expression; see comment on |
| 7293 // LoadTypeofExpression(). | 7301 // LoadTypeofExpression(). |
| 7294 LoadTypeofExpression(node->expression()); | 7302 LoadTypeofExpression(node->expression()); |
| (...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7960 bool CodeGenerator::HasValidEntryRegisters() { | 7968 bool CodeGenerator::HasValidEntryRegisters() { |
| 7961 return (allocator()->count(rax) == (frame()->is_used(rax) ? 1 : 0)) | 7969 return (allocator()->count(rax) == (frame()->is_used(rax) ? 1 : 0)) |
| 7962 && (allocator()->count(rbx) == (frame()->is_used(rbx) ? 1 : 0)) | 7970 && (allocator()->count(rbx) == (frame()->is_used(rbx) ? 1 : 0)) |
| 7963 && (allocator()->count(rcx) == (frame()->is_used(rcx) ? 1 : 0)) | 7971 && (allocator()->count(rcx) == (frame()->is_used(rcx) ? 1 : 0)) |
| 7964 && (allocator()->count(rdx) == (frame()->is_used(rdx) ? 1 : 0)) | 7972 && (allocator()->count(rdx) == (frame()->is_used(rdx) ? 1 : 0)) |
| 7965 && (allocator()->count(rdi) == (frame()->is_used(rdi) ? 1 : 0)) | 7973 && (allocator()->count(rdi) == (frame()->is_used(rdi) ? 1 : 0)) |
| 7966 && (allocator()->count(r8) == (frame()->is_used(r8) ? 1 : 0)) | 7974 && (allocator()->count(r8) == (frame()->is_used(r8) ? 1 : 0)) |
| 7967 && (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0)) | 7975 && (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0)) |
| 7968 && (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0)) | 7976 && (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0)) |
| 7969 && (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0)) | 7977 && (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0)) |
| 7970 && (allocator()->count(r12) == (frame()->is_used(r12) ? 1 : 0)); | 7978 && (allocator()->count(r15) == (frame()->is_used(r15) ? 1 : 0)); |
| 7971 } | 7979 } |
| 7972 #endif | 7980 #endif |
| 7973 | 7981 |
| 7974 | 7982 |
| 7975 | 7983 |
| 7976 // Emit a LoadIC call to get the value from receiver and leave it in | 7984 // Emit a LoadIC call to get the value from receiver and leave it in |
| 7977 // dst. The receiver register is restored after the call. | 7985 // dst. The receiver register is restored after the call. |
| 7978 class DeferredReferenceGetNamedValue: public DeferredCode { | 7986 class DeferredReferenceGetNamedValue: public DeferredCode { |
| 7979 public: | 7987 public: |
| 7980 DeferredReferenceGetNamedValue(Register dst, | 7988 DeferredReferenceGetNamedValue(Register dst, |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8083 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); | 8091 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); |
| 8084 | 8092 |
| 8085 if (!dst_.is(rax)) __ movq(dst_, rax); | 8093 if (!dst_.is(rax)) __ movq(dst_, rax); |
| 8086 } | 8094 } |
| 8087 | 8095 |
| 8088 | 8096 |
| 8089 class DeferredReferenceSetKeyedValue: public DeferredCode { | 8097 class DeferredReferenceSetKeyedValue: public DeferredCode { |
| 8090 public: | 8098 public: |
| 8091 DeferredReferenceSetKeyedValue(Register value, | 8099 DeferredReferenceSetKeyedValue(Register value, |
| 8092 Register key, | 8100 Register key, |
| 8093 Register receiver) | 8101 Register receiver, |
| 8094 : value_(value), key_(key), receiver_(receiver) { | 8102 StrictModeFlag strict_mode) |
| 8103 : value_(value), |
| 8104 key_(key), |
| 8105 receiver_(receiver), |
| 8106 strict_mode_(strict_mode) { |
| 8095 set_comment("[ DeferredReferenceSetKeyedValue"); | 8107 set_comment("[ DeferredReferenceSetKeyedValue"); |
| 8096 } | 8108 } |
| 8097 | 8109 |
| 8098 virtual void Generate(); | 8110 virtual void Generate(); |
| 8099 | 8111 |
| 8100 Label* patch_site() { return &patch_site_; } | 8112 Label* patch_site() { return &patch_site_; } |
| 8101 | 8113 |
| 8102 private: | 8114 private: |
| 8103 Register value_; | 8115 Register value_; |
| 8104 Register key_; | 8116 Register key_; |
| 8105 Register receiver_; | 8117 Register receiver_; |
| 8106 Label patch_site_; | 8118 Label patch_site_; |
| 8119 StrictModeFlag strict_mode_; |
| 8107 }; | 8120 }; |
| 8108 | 8121 |
| 8109 | 8122 |
| 8110 void DeferredReferenceSetKeyedValue::Generate() { | 8123 void DeferredReferenceSetKeyedValue::Generate() { |
| 8111 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); | 8124 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); |
| 8112 // Move value, receiver, and key to registers rax, rdx, and rcx, as | 8125 // Move value, receiver, and key to registers rax, rdx, and rcx, as |
| 8113 // the IC stub expects. | 8126 // the IC stub expects. |
| 8114 // Move value to rax, using xchg if the receiver or key is in rax. | 8127 // Move value to rax, using xchg if the receiver or key is in rax. |
| 8115 if (!value_.is(rax)) { | 8128 if (!value_.is(rax)) { |
| 8116 if (!receiver_.is(rax) && !key_.is(rax)) { | 8129 if (!receiver_.is(rax) && !key_.is(rax)) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8148 __ movq(rcx, key_); | 8161 __ movq(rcx, key_); |
| 8149 } | 8162 } |
| 8150 } else if (key_.is(rcx)) { | 8163 } else if (key_.is(rcx)) { |
| 8151 __ movq(rdx, receiver_); | 8164 __ movq(rdx, receiver_); |
| 8152 } else { | 8165 } else { |
| 8153 __ movq(rcx, key_); | 8166 __ movq(rcx, key_); |
| 8154 __ movq(rdx, receiver_); | 8167 __ movq(rdx, receiver_); |
| 8155 } | 8168 } |
| 8156 | 8169 |
| 8157 // Call the IC stub. | 8170 // Call the IC stub. |
| 8158 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 8171 Handle<Code> ic(Builtins::builtin( |
| 8172 (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict |
| 8173 : Builtins::KeyedStoreIC_Initialize)); |
| 8159 __ Call(ic, RelocInfo::CODE_TARGET); | 8174 __ Call(ic, RelocInfo::CODE_TARGET); |
| 8160 // The delta from the start of the map-compare instructions (initial movq) | 8175 // The delta from the start of the map-compare instructions (initial movq) |
| 8161 // to the test instruction. We use masm_-> directly here instead of the | 8176 // to the test instruction. We use masm_-> directly here instead of the |
| 8162 // __ macro because the macro sometimes uses macro expansion to turn | 8177 // __ macro because the macro sometimes uses macro expansion to turn |
| 8163 // into something that can't return a value. This is encountered | 8178 // into something that can't return a value. This is encountered |
| 8164 // when doing generated code coverage tests. | 8179 // when doing generated code coverage tests. |
| 8165 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 8180 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
| 8166 // Here we use masm_-> instead of the __ macro because this is the | 8181 // Here we use masm_-> instead of the __ macro because this is the |
| 8167 // instruction that gets patched and coverage code gets in the way. | 8182 // instruction that gets patched and coverage code gets in the way. |
| 8168 masm_->testl(rax, Immediate(-delta_to_patch_site)); | 8183 masm_->testl(rax, Immediate(-delta_to_patch_site)); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8215 DeferredReferenceGetNamedValue* deferred = | 8230 DeferredReferenceGetNamedValue* deferred = |
| 8216 new DeferredReferenceGetNamedValue(result.reg(), receiver.reg(), name); | 8231 new DeferredReferenceGetNamedValue(result.reg(), receiver.reg(), name); |
| 8217 | 8232 |
| 8218 // Check that the receiver is a heap object. | 8233 // Check that the receiver is a heap object. |
| 8219 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); | 8234 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
| 8220 | 8235 |
| 8221 __ bind(deferred->patch_site()); | 8236 __ bind(deferred->patch_site()); |
| 8222 // This is the map check instruction that will be patched (so we can't | 8237 // This is the map check instruction that will be patched (so we can't |
| 8223 // use the double underscore macro that may insert instructions). | 8238 // use the double underscore macro that may insert instructions). |
| 8224 // Initially use an invalid map to force a failure. | 8239 // Initially use an invalid map to force a failure. |
| 8225 masm()->Move(kScratchRegister, Factory::null_value()); | 8240 masm()->movq(kScratchRegister, Factory::null_value(), |
| 8241 RelocInfo::EMBEDDED_OBJECT); |
| 8226 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 8242 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
| 8227 kScratchRegister); | 8243 kScratchRegister); |
| 8228 // This branch is always a forwards branch so it's always a fixed | 8244 // This branch is always a forwards branch so it's always a fixed |
| 8229 // size which allows the assert below to succeed and patching to work. | 8245 // size which allows the assert below to succeed and patching to work. |
| 8230 // Don't use deferred->Branch(...), since that might add coverage code. | 8246 // Don't use deferred->Branch(...), since that might add coverage code. |
| 8231 masm()->j(not_equal, deferred->entry_label()); | 8247 masm()->j(not_equal, deferred->entry_label()); |
| 8232 | 8248 |
| 8233 // The delta from the patch label to the load offset must be | 8249 // The delta from the patch label to the load offset must be |
| 8234 // statically known. | 8250 // statically known. |
| 8235 ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) == | 8251 ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) == |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8291 Condition is_smi = masm()->CheckSmi(receiver.reg()); | 8307 Condition is_smi = masm()->CheckSmi(receiver.reg()); |
| 8292 slow.Branch(is_smi, &value, &receiver); | 8308 slow.Branch(is_smi, &value, &receiver); |
| 8293 | 8309 |
| 8294 // This is the map check instruction that will be patched. | 8310 // This is the map check instruction that will be patched. |
| 8295 // Initially use an invalid map to force a failure. The exact | 8311 // Initially use an invalid map to force a failure. The exact |
| 8296 // instruction sequence is important because we use the | 8312 // instruction sequence is important because we use the |
| 8297 // kOffsetToStoreInstruction constant for patching. We avoid using | 8313 // kOffsetToStoreInstruction constant for patching. We avoid using |
| 8298 // the __ macro for the following two instructions because it | 8314 // the __ macro for the following two instructions because it |
| 8299 // might introduce extra instructions. | 8315 // might introduce extra instructions. |
| 8300 __ bind(&patch_site); | 8316 __ bind(&patch_site); |
| 8301 masm()->Move(kScratchRegister, Factory::null_value()); | 8317 masm()->movq(kScratchRegister, Factory::null_value(), |
| 8318 RelocInfo::EMBEDDED_OBJECT); |
| 8302 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 8319 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
| 8303 kScratchRegister); | 8320 kScratchRegister); |
| 8304 // This branch is always a forwards branch so it's always a fixed size | 8321 // This branch is always a forwards branch so it's always a fixed size |
| 8305 // which allows the assert below to succeed and patching to work. | 8322 // which allows the assert below to succeed and patching to work. |
| 8306 slow.Branch(not_equal, &value, &receiver); | 8323 slow.Branch(not_equal, &value, &receiver); |
| 8307 | 8324 |
| 8308 // The delta from the patch label to the store offset must be | 8325 // The delta from the patch label to the store offset must be |
| 8309 // statically known. | 8326 // statically known. |
| 8310 ASSERT(masm()->SizeOfCodeGeneratedSince(&patch_site) == | 8327 ASSERT(masm()->SizeOfCodeGeneratedSince(&patch_site) == |
| 8311 StoreIC::kOffsetToStoreInstruction); | 8328 StoreIC::kOffsetToStoreInstruction); |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8492 bool value_is_constant = result.is_constant(); | 8509 bool value_is_constant = result.is_constant(); |
| 8493 | 8510 |
| 8494 // Make sure that value, key and receiver are in registers. | 8511 // Make sure that value, key and receiver are in registers. |
| 8495 result.ToRegister(); | 8512 result.ToRegister(); |
| 8496 key.ToRegister(); | 8513 key.ToRegister(); |
| 8497 receiver.ToRegister(); | 8514 receiver.ToRegister(); |
| 8498 | 8515 |
| 8499 DeferredReferenceSetKeyedValue* deferred = | 8516 DeferredReferenceSetKeyedValue* deferred = |
| 8500 new DeferredReferenceSetKeyedValue(result.reg(), | 8517 new DeferredReferenceSetKeyedValue(result.reg(), |
| 8501 key.reg(), | 8518 key.reg(), |
| 8502 receiver.reg()); | 8519 receiver.reg(), |
| 8520 strict_mode_flag()); |
| 8503 | 8521 |
| 8504 // Check that the receiver is not a smi. | 8522 // Check that the receiver is not a smi. |
| 8505 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); | 8523 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
| 8506 | 8524 |
| 8507 // Check that the key is a smi. | 8525 // Check that the key is a smi. |
| 8508 if (!key.is_smi()) { | 8526 if (!key.is_smi()) { |
| 8509 __ JumpIfNotSmi(key.reg(), deferred->entry_label()); | 8527 __ JumpIfNotSmi(key.reg(), deferred->entry_label()); |
| 8510 } else if (FLAG_debug_code) { | 8528 } else if (FLAG_debug_code) { |
| 8511 __ AbortIfNotSmi(key.reg()); | 8529 __ AbortIfNotSmi(key.reg()); |
| 8512 } | 8530 } |
| 8513 | 8531 |
| 8514 // Check that the receiver is a JSArray. | 8532 // Check that the receiver is a JSArray. |
| 8515 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister); | 8533 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister); |
| 8516 deferred->Branch(not_equal); | 8534 deferred->Branch(not_equal); |
| 8517 | 8535 |
| 8518 // Check that the key is within bounds. Both the key and the length of | |
| 8519 // the JSArray are smis. Use unsigned comparison to handle negative keys. | |
| 8520 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset), | |
| 8521 key.reg()); | |
| 8522 deferred->Branch(below_equal); | |
| 8523 | |
| 8524 // Get the elements array from the receiver and check that it is not a | 8536 // Get the elements array from the receiver and check that it is not a |
| 8525 // dictionary. | 8537 // dictionary. |
| 8526 __ movq(tmp.reg(), | 8538 __ movq(tmp.reg(), |
| 8527 FieldOperand(receiver.reg(), JSArray::kElementsOffset)); | 8539 FieldOperand(receiver.reg(), JSArray::kElementsOffset)); |
| 8528 | 8540 |
| 8529 // Check whether it is possible to omit the write barrier. If the elements | 8541 // Check whether it is possible to omit the write barrier. If the elements |
| 8530 // array is in new space or the value written is a smi we can safely update | 8542 // array is in new space or the value written is a smi we can safely update |
| 8531 // the elements array without write barrier. | 8543 // the elements array without write barrier. |
| 8532 Label in_new_space; | 8544 Label in_new_space; |
| 8533 __ InNewSpace(tmp.reg(), tmp2.reg(), equal, &in_new_space); | 8545 __ InNewSpace(tmp.reg(), tmp2.reg(), equal, &in_new_space); |
| 8534 if (!value_is_constant) { | 8546 if (!value_is_constant) { |
| 8535 __ JumpIfNotSmi(result.reg(), deferred->entry_label()); | 8547 __ JumpIfNotSmi(result.reg(), deferred->entry_label()); |
| 8536 } | 8548 } |
| 8537 | 8549 |
| 8538 __ bind(&in_new_space); | 8550 __ bind(&in_new_space); |
| 8539 | 8551 |
| 8540 // Bind the deferred code patch site to be able to locate the fixed | 8552 // Bind the deferred code patch site to be able to locate the fixed |
| 8541 // array map comparison. When debugging, we patch this comparison to | 8553 // array map comparison. When debugging, we patch this comparison to |
| 8542 // always fail so that we will hit the IC call in the deferred code | 8554 // always fail so that we will hit the IC call in the deferred code |
| 8543 // which will allow the debugger to break for fast case stores. | 8555 // which will allow the debugger to break for fast case stores. |
| 8544 __ bind(deferred->patch_site()); | 8556 __ bind(deferred->patch_site()); |
| 8545 // Avoid using __ to ensure the distance from patch_site | 8557 // Avoid using __ to ensure the distance from patch_site |
| 8546 // to the map address is always the same. | 8558 // to the map address is always the same. |
| 8547 masm()->movq(kScratchRegister, Factory::fixed_array_map(), | 8559 masm()->movq(kScratchRegister, Factory::fixed_array_map(), |
| 8548 RelocInfo::EMBEDDED_OBJECT); | 8560 RelocInfo::EMBEDDED_OBJECT); |
| 8549 __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | 8561 __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
| 8550 kScratchRegister); | 8562 kScratchRegister); |
| 8551 deferred->Branch(not_equal); | 8563 deferred->Branch(not_equal); |
| 8552 | 8564 |
| 8565 // Check that the key is within bounds. Both the key and the length of |
| 8566 // the JSArray are smis (because the fixed array check above ensures the |
| 8567 // elements are in fast case). Use unsigned comparison to handle negative |
| 8568 // keys. |
| 8569 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset), |
| 8570 key.reg()); |
| 8571 deferred->Branch(below_equal); |
| 8572 |
| 8553 // Store the value. | 8573 // Store the value. |
| 8554 SmiIndex index = | 8574 SmiIndex index = |
| 8555 masm()->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); | 8575 masm()->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); |
| 8556 __ movq(FieldOperand(tmp.reg(), | 8576 __ movq(FieldOperand(tmp.reg(), |
| 8557 index.reg, | 8577 index.reg, |
| 8558 index.scale, | 8578 index.scale, |
| 8559 FixedArray::kHeaderSize), | 8579 FixedArray::kHeaderSize), |
| 8560 result.reg()); | 8580 result.reg()); |
| 8561 __ IncrementCounter(&Counters::keyed_store_inline, 1); | 8581 __ IncrementCounter(&Counters::keyed_store_inline, 1); |
| 8562 | 8582 |
| 8563 deferred->BindExit(); | 8583 deferred->BindExit(); |
| 8564 } else { | 8584 } else { |
| 8565 result = frame()->CallKeyedStoreIC(); | 8585 result = frame()->CallKeyedStoreIC(strict_mode_flag()); |
| 8566 // Make sure that we do not have a test instruction after the | 8586 // Make sure that we do not have a test instruction after the |
| 8567 // call. A test instruction after the call is used to | 8587 // call. A test instruction after the call is used to |
| 8568 // indicate that we have generated an inline version of the | 8588 // indicate that we have generated an inline version of the |
| 8569 // keyed store. | 8589 // keyed store. |
| 8570 __ nop(); | 8590 __ nop(); |
| 8571 } | 8591 } |
| 8572 ASSERT(frame()->height() == original_height - 3); | 8592 ASSERT(frame()->height() == original_height - 3); |
| 8573 return result; | 8593 return result; |
| 8574 } | 8594 } |
| 8575 | 8595 |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8834 } | 8854 } |
| 8835 | 8855 |
| 8836 #endif | 8856 #endif |
| 8837 | 8857 |
| 8838 | 8858 |
| 8839 #undef __ | 8859 #undef __ |
| 8840 | 8860 |
| 8841 } } // namespace v8::internal | 8861 } } // namespace v8::internal |
| 8842 | 8862 |
| 8843 #endif // V8_TARGET_ARCH_X64 | 8863 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |