OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 __ int3(); | 131 __ int3(); |
132 } | 132 } |
133 #endif | 133 #endif |
134 | 134 |
135 // Strict mode functions and builtins need to replace the receiver | 135 // Strict mode functions and builtins need to replace the receiver |
136 // with undefined when called as functions (without an explicit | 136 // with undefined when called as functions (without an explicit |
137 // receiver object). ecx is zero for method calls and non-zero for | 137 // receiver object). ecx is zero for method calls and non-zero for |
138 // function calls. | 138 // function calls. |
139 if (info->is_strict_mode() || info->is_native()) { | 139 if (info->is_strict_mode() || info->is_native()) { |
140 Label ok; | 140 Label ok; |
141 __ test(ecx, Operand(ecx)); | 141 __ test(ecx, ecx); |
142 __ j(zero, &ok, Label::kNear); | 142 __ j(zero, &ok, Label::kNear); |
143 // +1 for return address. | 143 // +1 for return address. |
144 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; | 144 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; |
145 __ mov(Operand(esp, receiver_offset), | 145 __ mov(Operand(esp, receiver_offset), |
146 Immediate(isolate()->factory()->undefined_value())); | 146 Immediate(isolate()->factory()->undefined_value())); |
147 __ bind(&ok); | 147 __ bind(&ok); |
148 } | 148 } |
149 | 149 |
| 150 // Open a frame scope to indicate that there is a frame on the stack. The |
| 151 // MANUAL indicates that the scope shouldn't actually generate code to set up |
| 152 // the frame (that is done below). |
| 153 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
| 154 |
150 __ push(ebp); // Caller's frame pointer. | 155 __ push(ebp); // Caller's frame pointer. |
151 __ mov(ebp, esp); | 156 __ mov(ebp, esp); |
152 __ push(esi); // Callee's context. | 157 __ push(esi); // Callee's context. |
153 __ push(edi); // Callee's JS Function. | 158 __ push(edi); // Callee's JS Function. |
154 | 159 |
155 { Comment cmnt(masm_, "[ Allocate locals"); | 160 { Comment cmnt(masm_, "[ Allocate locals"); |
156 int locals_count = info->scope()->num_stack_slots(); | 161 int locals_count = info->scope()->num_stack_slots(); |
157 if (locals_count == 1) { | 162 if (locals_count == 1) { |
158 __ push(Immediate(isolate()->factory()->undefined_value())); | 163 __ push(Immediate(isolate()->factory()->undefined_value())); |
159 } else if (locals_count > 1) { | 164 } else if (locals_count > 1) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 for (int i = 0; i < num_parameters; i++) { | 198 for (int i = 0; i < num_parameters; i++) { |
194 Variable* var = scope()->parameter(i); | 199 Variable* var = scope()->parameter(i); |
195 if (var->IsContextSlot()) { | 200 if (var->IsContextSlot()) { |
196 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 201 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
197 (num_parameters - 1 - i) * kPointerSize; | 202 (num_parameters - 1 - i) * kPointerSize; |
198 // Load parameter from stack. | 203 // Load parameter from stack. |
199 __ mov(eax, Operand(ebp, parameter_offset)); | 204 __ mov(eax, Operand(ebp, parameter_offset)); |
200 // Store it in the context. | 205 // Store it in the context. |
201 int context_offset = Context::SlotOffset(var->index()); | 206 int context_offset = Context::SlotOffset(var->index()); |
202 __ mov(Operand(esi, context_offset), eax); | 207 __ mov(Operand(esi, context_offset), eax); |
203 // Update the write barrier. This clobbers all involved | 208 // Update the write barrier. This clobbers eax and ebx. |
204 // registers, so we have use a third register to avoid | 209 __ RecordWriteContextSlot(esi, |
205 // clobbering esi. | 210 context_offset, |
206 __ mov(ecx, esi); | 211 eax, |
207 __ RecordWrite(ecx, context_offset, eax, ebx); | 212 ebx, |
| 213 kDontSaveFPRegs); |
208 } | 214 } |
209 } | 215 } |
210 } | 216 } |
211 | 217 |
212 Variable* arguments = scope()->arguments(); | 218 Variable* arguments = scope()->arguments(); |
213 if (arguments != NULL) { | 219 if (arguments != NULL) { |
214 // Function uses arguments object. | 220 // Function uses arguments object. |
215 Comment cmnt(masm_, "[ Allocate arguments object"); | 221 Comment cmnt(masm_, "[ Allocate arguments object"); |
216 if (function_in_register) { | 222 if (function_in_register) { |
217 __ push(edi); | 223 __ push(edi); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 // for the debugger's requirements. | 364 // for the debugger's requirements. |
359 ASSERT(Assembler::kJSReturnSequenceLength <= | 365 ASSERT(Assembler::kJSReturnSequenceLength <= |
360 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 366 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
361 #endif | 367 #endif |
362 } | 368 } |
363 } | 369 } |
364 | 370 |
365 | 371 |
366 void FullCodeGenerator::verify_stack_height() { | 372 void FullCodeGenerator::verify_stack_height() { |
367 ASSERT(FLAG_verify_stack_height); | 373 ASSERT(FLAG_verify_stack_height); |
368 __ sub(Operand(ebp), Immediate(kPointerSize * stack_height())); | 374 __ sub(ebp, Immediate(kPointerSize * stack_height())); |
369 __ cmp(ebp, Operand(esp)); | 375 __ cmp(ebp, esp); |
370 __ Assert(equal, "Full codegen stack height not as expected."); | 376 __ Assert(equal, "Full codegen stack height not as expected."); |
371 __ add(Operand(ebp), Immediate(kPointerSize * stack_height())); | 377 __ add(ebp, Immediate(kPointerSize * stack_height())); |
372 } | 378 } |
373 | 379 |
374 | 380 |
375 void FullCodeGenerator::EffectContext::Plug(Variable* var) const { | 381 void FullCodeGenerator::EffectContext::Plug(Variable* var) const { |
376 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 382 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
377 } | 383 } |
378 | 384 |
379 | 385 |
380 void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const { | 386 void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const { |
381 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 387 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
590 } | 596 } |
591 | 597 |
592 | 598 |
593 void FullCodeGenerator::DoTest(Expression* condition, | 599 void FullCodeGenerator::DoTest(Expression* condition, |
594 Label* if_true, | 600 Label* if_true, |
595 Label* if_false, | 601 Label* if_false, |
596 Label* fall_through) { | 602 Label* fall_through) { |
597 ToBooleanStub stub(result_register()); | 603 ToBooleanStub stub(result_register()); |
598 __ push(result_register()); | 604 __ push(result_register()); |
599 __ CallStub(&stub, condition->test_id()); | 605 __ CallStub(&stub, condition->test_id()); |
600 __ test(result_register(), Operand(result_register())); | 606 __ test(result_register(), result_register()); |
601 // The stub returns nonzero for true. | 607 // The stub returns nonzero for true. |
602 Split(not_zero, if_true, if_false, fall_through); | 608 Split(not_zero, if_true, if_false, fall_through); |
603 } | 609 } |
604 | 610 |
605 | 611 |
606 void FullCodeGenerator::Split(Condition cc, | 612 void FullCodeGenerator::Split(Condition cc, |
607 Label* if_true, | 613 Label* if_true, |
608 Label* if_false, | 614 Label* if_false, |
609 Label* fall_through) { | 615 Label* fall_through) { |
610 if (if_false == fall_through) { | 616 if (if_false == fall_through) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 void FullCodeGenerator::SetVar(Variable* var, | 660 void FullCodeGenerator::SetVar(Variable* var, |
655 Register src, | 661 Register src, |
656 Register scratch0, | 662 Register scratch0, |
657 Register scratch1) { | 663 Register scratch1) { |
658 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); | 664 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); |
659 ASSERT(!scratch0.is(src)); | 665 ASSERT(!scratch0.is(src)); |
660 ASSERT(!scratch0.is(scratch1)); | 666 ASSERT(!scratch0.is(scratch1)); |
661 ASSERT(!scratch1.is(src)); | 667 ASSERT(!scratch1.is(src)); |
662 MemOperand location = VarOperand(var, scratch0); | 668 MemOperand location = VarOperand(var, scratch0); |
663 __ mov(location, src); | 669 __ mov(location, src); |
| 670 |
664 // Emit the write barrier code if the location is in the heap. | 671 // Emit the write barrier code if the location is in the heap. |
665 if (var->IsContextSlot()) { | 672 if (var->IsContextSlot()) { |
666 int offset = Context::SlotOffset(var->index()); | 673 int offset = Context::SlotOffset(var->index()); |
667 ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi)); | 674 ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi)); |
668 __ RecordWrite(scratch0, offset, src, scratch1); | 675 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs); |
669 } | 676 } |
670 } | 677 } |
671 | 678 |
672 | 679 |
673 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 680 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
674 bool should_normalize, | 681 bool should_normalize, |
675 Label* if_true, | 682 Label* if_true, |
676 Label* if_false) { | 683 Label* if_false) { |
677 // Only prepare for bailouts before splits if we're in a test | 684 // Only prepare for bailouts before splits if we're in a test |
678 // context. Otherwise, we let the Visit function deal with the | 685 // context. Otherwise, we let the Visit function deal with the |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); | 738 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); |
732 __ cmp(ebx, isolate()->factory()->with_context_map()); | 739 __ cmp(ebx, isolate()->factory()->with_context_map()); |
733 __ Check(not_equal, "Declaration in with context."); | 740 __ Check(not_equal, "Declaration in with context."); |
734 __ cmp(ebx, isolate()->factory()->catch_context_map()); | 741 __ cmp(ebx, isolate()->factory()->catch_context_map()); |
735 __ Check(not_equal, "Declaration in catch context."); | 742 __ Check(not_equal, "Declaration in catch context."); |
736 } | 743 } |
737 if (function != NULL) { | 744 if (function != NULL) { |
738 Comment cmnt(masm_, "[ Declaration"); | 745 Comment cmnt(masm_, "[ Declaration"); |
739 VisitForAccumulatorValue(function); | 746 VisitForAccumulatorValue(function); |
740 __ mov(ContextOperand(esi, variable->index()), result_register()); | 747 __ mov(ContextOperand(esi, variable->index()), result_register()); |
741 int offset = Context::SlotOffset(variable->index()); | 748 // We know that we have written a function, which is not a smi. |
742 __ mov(ebx, esi); | 749 __ RecordWriteContextSlot(esi, |
743 __ RecordWrite(ebx, offset, result_register(), ecx); | 750 Context::SlotOffset(variable->index()), |
| 751 result_register(), |
| 752 ecx, |
| 753 kDontSaveFPRegs, |
| 754 EMIT_REMEMBERED_SET, |
| 755 OMIT_SMI_CHECK); |
744 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 756 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
745 } else if (mode == Variable::CONST || mode == Variable::LET) { | 757 } else if (mode == Variable::CONST || mode == Variable::LET) { |
746 Comment cmnt(masm_, "[ Declaration"); | 758 Comment cmnt(masm_, "[ Declaration"); |
747 __ mov(ContextOperand(esi, variable->index()), | 759 __ mov(ContextOperand(esi, variable->index()), |
748 Immediate(isolate()->factory()->the_hole_value())); | 760 Immediate(isolate()->factory()->the_hole_value())); |
749 // No write barrier since the hole value is in old space. | 761 // No write barrier since the hole value is in old space. |
750 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 762 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
751 } | 763 } |
752 break; | 764 break; |
753 | 765 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
828 // Compile the label expression. | 840 // Compile the label expression. |
829 VisitForAccumulatorValue(clause->label()); | 841 VisitForAccumulatorValue(clause->label()); |
830 | 842 |
831 // Perform the comparison as if via '==='. | 843 // Perform the comparison as if via '==='. |
832 __ mov(edx, Operand(esp, 0)); // Switch value. | 844 __ mov(edx, Operand(esp, 0)); // Switch value. |
833 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); | 845 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); |
834 JumpPatchSite patch_site(masm_); | 846 JumpPatchSite patch_site(masm_); |
835 if (inline_smi_code) { | 847 if (inline_smi_code) { |
836 Label slow_case; | 848 Label slow_case; |
837 __ mov(ecx, edx); | 849 __ mov(ecx, edx); |
838 __ or_(ecx, Operand(eax)); | 850 __ or_(ecx, eax); |
839 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); | 851 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); |
840 | 852 |
841 __ cmp(edx, Operand(eax)); | 853 __ cmp(edx, eax); |
842 __ j(not_equal, &next_test); | 854 __ j(not_equal, &next_test); |
843 __ Drop(1); // Switch value is no longer needed. | 855 __ Drop(1); // Switch value is no longer needed. |
844 __ jmp(clause->body_target()); | 856 __ jmp(clause->body_target()); |
845 __ bind(&slow_case); | 857 __ bind(&slow_case); |
846 } | 858 } |
847 | 859 |
848 // Record position before stub call for type feedback. | 860 // Record position before stub call for type feedback. |
849 SetSourcePosition(clause->position()); | 861 SetSourcePosition(clause->position()); |
850 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); | 862 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); |
851 __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId()); | 863 __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId()); |
852 patch_site.EmitPatchInfo(); | 864 patch_site.EmitPatchInfo(); |
853 __ test(eax, Operand(eax)); | 865 __ test(eax, eax); |
854 __ j(not_equal, &next_test); | 866 __ j(not_equal, &next_test); |
855 __ Drop(1); // Switch value is no longer needed. | 867 __ Drop(1); // Switch value is no longer needed. |
856 __ jmp(clause->body_target()); | 868 __ jmp(clause->body_target()); |
857 } | 869 } |
858 | 870 |
859 // Discard the test value and jump to the default if present, otherwise to | 871 // Discard the test value and jump to the default if present, otherwise to |
860 // the end of the statement. | 872 // the end of the statement. |
861 __ bind(&next_test); | 873 __ bind(&next_test); |
862 __ Drop(1); // Switch value is no longer needed. | 874 __ Drop(1); // Switch value is no longer needed. |
863 if (default_clause == NULL) { | 875 if (default_clause == NULL) { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
932 __ JumpIfSmi(edx, &call_runtime); | 944 __ JumpIfSmi(edx, &call_runtime); |
933 | 945 |
934 // Check that there is an enum cache in the non-empty instance | 946 // Check that there is an enum cache in the non-empty instance |
935 // descriptors (edx). This is the case if the next enumeration | 947 // descriptors (edx). This is the case if the next enumeration |
936 // index field does not contain a smi. | 948 // index field does not contain a smi. |
937 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | 949 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
938 __ JumpIfSmi(edx, &call_runtime); | 950 __ JumpIfSmi(edx, &call_runtime); |
939 | 951 |
940 // For all objects but the receiver, check that the cache is empty. | 952 // For all objects but the receiver, check that the cache is empty. |
941 Label check_prototype; | 953 Label check_prototype; |
942 __ cmp(ecx, Operand(eax)); | 954 __ cmp(ecx, eax); |
943 __ j(equal, &check_prototype, Label::kNear); | 955 __ j(equal, &check_prototype, Label::kNear); |
944 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 956 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
945 __ cmp(edx, isolate()->factory()->empty_fixed_array()); | 957 __ cmp(edx, isolate()->factory()->empty_fixed_array()); |
946 __ j(not_equal, &call_runtime); | 958 __ j(not_equal, &call_runtime); |
947 | 959 |
948 // Load the prototype from the map and loop if non-null. | 960 // Load the prototype from the map and loop if non-null. |
949 __ bind(&check_prototype); | 961 __ bind(&check_prototype); |
950 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); | 962 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); |
951 __ cmp(ecx, isolate()->factory()->null_value()); | 963 __ cmp(ecx, isolate()->factory()->null_value()); |
952 __ j(not_equal, &next); | 964 __ j(not_equal, &next); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1014 __ mov(ecx, Operand(esp, 4 * kPointerSize)); | 1026 __ mov(ecx, Operand(esp, 4 * kPointerSize)); |
1015 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset)); | 1027 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset)); |
1016 __ j(equal, &update_each, Label::kNear); | 1028 __ j(equal, &update_each, Label::kNear); |
1017 | 1029 |
1018 // Convert the entry to a string or null if it isn't a property | 1030 // Convert the entry to a string or null if it isn't a property |
1019 // anymore. If the property has been removed while iterating, we | 1031 // anymore. If the property has been removed while iterating, we |
1020 // just skip it. | 1032 // just skip it. |
1021 __ push(ecx); // Enumerable. | 1033 __ push(ecx); // Enumerable. |
1022 __ push(ebx); // Current entry. | 1034 __ push(ebx); // Current entry. |
1023 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); | 1035 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
1024 __ test(eax, Operand(eax)); | 1036 __ test(eax, eax); |
1025 __ j(equal, loop_statement.continue_label()); | 1037 __ j(equal, loop_statement.continue_label()); |
1026 __ mov(ebx, Operand(eax)); | 1038 __ mov(ebx, eax); |
1027 | 1039 |
1028 // Update the 'each' property or variable from the possibly filtered | 1040 // Update the 'each' property or variable from the possibly filtered |
1029 // entry in register ebx. | 1041 // entry in register ebx. |
1030 __ bind(&update_each); | 1042 __ bind(&update_each); |
1031 __ mov(result_register(), ebx); | 1043 __ mov(result_register(), ebx); |
1032 // Perform the assignment as if via '='. | 1044 // Perform the assignment as if via '='. |
1033 { EffectContext context(this); | 1045 { EffectContext context(this); |
1034 EmitAssignment(stmt->each(), stmt->AssignmentId()); | 1046 EmitAssignment(stmt->each(), stmt->AssignmentId()); |
1035 } | 1047 } |
1036 | 1048 |
1037 // Generate code for the body of the loop. | 1049 // Generate code for the body of the loop. |
1038 Visit(stmt->body()); | 1050 Visit(stmt->body()); |
1039 | 1051 |
1040 // Generate code for going to the next element by incrementing the | 1052 // Generate code for going to the next element by incrementing the |
1041 // index (smi) stored on top of the stack. | 1053 // index (smi) stored on top of the stack. |
1042 __ bind(loop_statement.continue_label()); | 1054 __ bind(loop_statement.continue_label()); |
1043 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); | 1055 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); |
1044 | 1056 |
1045 EmitStackCheck(stmt); | 1057 EmitStackCheck(stmt); |
1046 __ jmp(&loop); | 1058 __ jmp(&loop); |
1047 | 1059 |
1048 // Remove the pointers stored on the stack. | 1060 // Remove the pointers stored on the stack. |
1049 __ bind(loop_statement.break_label()); | 1061 __ bind(loop_statement.break_label()); |
1050 __ add(Operand(esp), Immediate(5 * kPointerSize)); | 1062 __ add(esp, Immediate(5 * kPointerSize)); |
1051 | 1063 |
1052 decrement_stack_height(ForIn::kElementCount); | 1064 decrement_stack_height(ForIn::kElementCount); |
1053 // Exit and decrement the loop depth. | 1065 // Exit and decrement the loop depth. |
1054 __ bind(&exit); | 1066 __ bind(&exit); |
1055 decrement_loop_depth(); | 1067 decrement_loop_depth(); |
1056 } | 1068 } |
1057 | 1069 |
1058 | 1070 |
1059 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, | 1071 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, |
1060 bool pretenure) { | 1072 bool pretenure) { |
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1473 increment_stack_height(); | 1485 increment_stack_height(); |
1474 } | 1486 } |
1475 VisitForAccumulatorValue(subexpr); | 1487 VisitForAccumulatorValue(subexpr); |
1476 | 1488 |
1477 // Store the subexpression value in the array's elements. | 1489 // Store the subexpression value in the array's elements. |
1478 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. | 1490 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. |
1479 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); | 1491 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
1480 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1492 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
1481 __ mov(FieldOperand(ebx, offset), result_register()); | 1493 __ mov(FieldOperand(ebx, offset), result_register()); |
1482 | 1494 |
| 1495 Label no_map_change; |
| 1496 __ JumpIfSmi(result_register(), &no_map_change); |
1483 // Update the write barrier for the array store. | 1497 // Update the write barrier for the array store. |
1484 __ RecordWrite(ebx, offset, result_register(), ecx); | 1498 __ RecordWriteField(ebx, offset, result_register(), ecx, |
| 1499 kDontSaveFPRegs, |
| 1500 EMIT_REMEMBERED_SET, |
| 1501 OMIT_SMI_CHECK); |
| 1502 if (FLAG_smi_only_arrays) { |
| 1503 __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset)); |
| 1504 __ CheckFastSmiOnlyElements(edi, &no_map_change, Label::kNear); |
| 1505 __ push(Operand(esp, 0)); |
| 1506 __ CallRuntime(Runtime::kNonSmiElementStored, 1); |
| 1507 } |
| 1508 __ bind(&no_map_change); |
1485 | 1509 |
1486 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1510 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
1487 } | 1511 } |
1488 | 1512 |
1489 if (result_saved) { | 1513 if (result_saved) { |
1490 context()->PlugTOS(); | 1514 context()->PlugTOS(); |
1491 } else { | 1515 } else { |
1492 context()->Plug(eax); | 1516 context()->Plug(eax); |
1493 } | 1517 } |
1494 } | 1518 } |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1634 Token::Value op, | 1658 Token::Value op, |
1635 OverwriteMode mode, | 1659 OverwriteMode mode, |
1636 Expression* left, | 1660 Expression* left, |
1637 Expression* right) { | 1661 Expression* right) { |
1638 // Do combined smi check of the operands. Left operand is on the | 1662 // Do combined smi check of the operands. Left operand is on the |
1639 // stack. Right operand is in eax. | 1663 // stack. Right operand is in eax. |
1640 Label smi_case, done, stub_call; | 1664 Label smi_case, done, stub_call; |
1641 __ pop(edx); | 1665 __ pop(edx); |
1642 decrement_stack_height(); | 1666 decrement_stack_height(); |
1643 __ mov(ecx, eax); | 1667 __ mov(ecx, eax); |
1644 __ or_(eax, Operand(edx)); | 1668 __ or_(eax, edx); |
1645 JumpPatchSite patch_site(masm_); | 1669 JumpPatchSite patch_site(masm_); |
1646 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); | 1670 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); |
1647 | 1671 |
1648 __ bind(&stub_call); | 1672 __ bind(&stub_call); |
1649 __ mov(eax, ecx); | 1673 __ mov(eax, ecx); |
1650 BinaryOpStub stub(op, mode); | 1674 BinaryOpStub stub(op, mode); |
1651 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); | 1675 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
1652 patch_site.EmitPatchInfo(); | 1676 patch_site.EmitPatchInfo(); |
1653 __ jmp(&done, Label::kNear); | 1677 __ jmp(&done, Label::kNear); |
1654 | 1678 |
(...skipping 29 matching lines...) Expand all Loading... |
1684 __ shr_cl(eax); | 1708 __ shr_cl(eax); |
1685 __ test(eax, Immediate(0xc0000000)); | 1709 __ test(eax, Immediate(0xc0000000)); |
1686 __ j(zero, &result_ok); | 1710 __ j(zero, &result_ok); |
1687 __ SmiTag(ecx); | 1711 __ SmiTag(ecx); |
1688 __ jmp(&stub_call); | 1712 __ jmp(&stub_call); |
1689 __ bind(&result_ok); | 1713 __ bind(&result_ok); |
1690 __ SmiTag(eax); | 1714 __ SmiTag(eax); |
1691 break; | 1715 break; |
1692 } | 1716 } |
1693 case Token::ADD: | 1717 case Token::ADD: |
1694 __ add(eax, Operand(ecx)); | 1718 __ add(eax, ecx); |
1695 __ j(overflow, &stub_call); | 1719 __ j(overflow, &stub_call); |
1696 break; | 1720 break; |
1697 case Token::SUB: | 1721 case Token::SUB: |
1698 __ sub(eax, Operand(ecx)); | 1722 __ sub(eax, ecx); |
1699 __ j(overflow, &stub_call); | 1723 __ j(overflow, &stub_call); |
1700 break; | 1724 break; |
1701 case Token::MUL: { | 1725 case Token::MUL: { |
1702 __ SmiUntag(eax); | 1726 __ SmiUntag(eax); |
1703 __ imul(eax, Operand(ecx)); | 1727 __ imul(eax, ecx); |
1704 __ j(overflow, &stub_call); | 1728 __ j(overflow, &stub_call); |
1705 __ test(eax, Operand(eax)); | 1729 __ test(eax, eax); |
1706 __ j(not_zero, &done, Label::kNear); | 1730 __ j(not_zero, &done, Label::kNear); |
1707 __ mov(ebx, edx); | 1731 __ mov(ebx, edx); |
1708 __ or_(ebx, Operand(ecx)); | 1732 __ or_(ebx, ecx); |
1709 __ j(negative, &stub_call); | 1733 __ j(negative, &stub_call); |
1710 break; | 1734 break; |
1711 } | 1735 } |
1712 case Token::BIT_OR: | 1736 case Token::BIT_OR: |
1713 __ or_(eax, Operand(ecx)); | 1737 __ or_(eax, ecx); |
1714 break; | 1738 break; |
1715 case Token::BIT_AND: | 1739 case Token::BIT_AND: |
1716 __ and_(eax, Operand(ecx)); | 1740 __ and_(eax, ecx); |
1717 break; | 1741 break; |
1718 case Token::BIT_XOR: | 1742 case Token::BIT_XOR: |
1719 __ xor_(eax, Operand(ecx)); | 1743 __ xor_(eax, ecx); |
1720 break; | 1744 break; |
1721 default: | 1745 default: |
1722 UNREACHABLE(); | 1746 UNREACHABLE(); |
1723 } | 1747 } |
1724 | 1748 |
1725 __ bind(&done); | 1749 __ bind(&done); |
1726 context()->Plug(eax); | 1750 context()->Plug(eax); |
1727 } | 1751 } |
1728 | 1752 |
1729 | 1753 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1852 MemOperand location = VarOperand(var, ecx); | 1876 MemOperand location = VarOperand(var, ecx); |
1853 __ mov(edx, location); | 1877 __ mov(edx, location); |
1854 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1878 __ cmp(edx, isolate()->factory()->the_hole_value()); |
1855 __ j(not_equal, &assign, Label::kNear); | 1879 __ j(not_equal, &assign, Label::kNear); |
1856 __ push(Immediate(var->name())); | 1880 __ push(Immediate(var->name())); |
1857 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1881 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1858 __ bind(&assign); | 1882 __ bind(&assign); |
1859 __ mov(location, eax); | 1883 __ mov(location, eax); |
1860 if (var->IsContextSlot()) { | 1884 if (var->IsContextSlot()) { |
1861 __ mov(edx, eax); | 1885 __ mov(edx, eax); |
1862 __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx); | 1886 int offset = Context::SlotOffset(var->index()); |
| 1887 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); |
1863 } | 1888 } |
1864 } | 1889 } |
1865 | 1890 |
1866 } else if (var->mode() != Variable::CONST) { | 1891 } else if (var->mode() != Variable::CONST) { |
1867 // Assignment to var or initializing assignment to let. | 1892 // Assignment to var or initializing assignment to let. |
1868 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1893 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1869 MemOperand location = VarOperand(var, ecx); | 1894 MemOperand location = VarOperand(var, ecx); |
1870 if (FLAG_debug_code && op == Token::INIT_LET) { | 1895 if (FLAG_debug_code && op == Token::INIT_LET) { |
1871 // Check for an uninitialized let binding. | 1896 // Check for an uninitialized let binding. |
1872 __ mov(edx, location); | 1897 __ mov(edx, location); |
1873 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1898 __ cmp(edx, isolate()->factory()->the_hole_value()); |
1874 __ Check(equal, "Let binding re-initialization."); | 1899 __ Check(equal, "Let binding re-initialization."); |
1875 } | 1900 } |
1876 // Perform the assignment. | 1901 // Perform the assignment. |
1877 __ mov(location, eax); | 1902 __ mov(location, eax); |
1878 if (var->IsContextSlot()) { | 1903 if (var->IsContextSlot()) { |
1879 __ mov(edx, eax); | 1904 __ mov(edx, eax); |
1880 __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx); | 1905 int offset = Context::SlotOffset(var->index()); |
| 1906 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); |
1881 } | 1907 } |
1882 } else { | 1908 } else { |
1883 ASSERT(var->IsLookupSlot()); | 1909 ASSERT(var->IsLookupSlot()); |
1884 __ push(eax); // Value. | 1910 __ push(eax); // Value. |
1885 __ push(esi); // Context. | 1911 __ push(esi); // Context. |
1886 __ push(Immediate(var->name())); | 1912 __ push(Immediate(var->name())); |
1887 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 1913 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
1888 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 1914 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1889 } | 1915 } |
1890 } | 1916 } |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2062 // Code common for calls using the call stub. | 2088 // Code common for calls using the call stub. |
2063 ZoneList<Expression*>* args = expr->arguments(); | 2089 ZoneList<Expression*>* args = expr->arguments(); |
2064 int arg_count = args->length(); | 2090 int arg_count = args->length(); |
2065 { PreservePositionScope scope(masm()->positions_recorder()); | 2091 { PreservePositionScope scope(masm()->positions_recorder()); |
2066 for (int i = 0; i < arg_count; i++) { | 2092 for (int i = 0; i < arg_count; i++) { |
2067 VisitForStackValue(args->at(i)); | 2093 VisitForStackValue(args->at(i)); |
2068 } | 2094 } |
2069 } | 2095 } |
2070 // Record source position for debugger. | 2096 // Record source position for debugger. |
2071 SetSourcePosition(expr->position()); | 2097 SetSourcePosition(expr->position()); |
| 2098 |
| 2099 // Record call targets in unoptimized code, but not in the snapshot. |
| 2100 bool record_call_target = !Serializer::enabled(); |
| 2101 if (record_call_target) { |
| 2102 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); |
| 2103 } |
2072 CallFunctionStub stub(arg_count, flags); | 2104 CallFunctionStub stub(arg_count, flags); |
2073 __ CallStub(&stub); | 2105 __ CallStub(&stub); |
| 2106 if (record_call_target) { |
| 2107 // There is a one element cache in the instruction stream. |
| 2108 #ifdef DEBUG |
| 2109 int return_site_offset = masm()->pc_offset(); |
| 2110 #endif |
| 2111 Handle<Object> uninitialized = |
| 2112 CallFunctionStub::UninitializedSentinel(isolate()); |
| 2113 Handle<JSGlobalPropertyCell> cell = |
| 2114 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); |
| 2115 __ test(eax, Immediate(cell)); |
| 2116 // Patching code in the stub assumes the opcode is 1 byte and there is |
| 2117 // word for a pointer in the operand. |
| 2118 ASSERT(masm()->pc_offset() - return_site_offset >= 1 + kPointerSize); |
| 2119 } |
| 2120 |
2074 RecordJSReturnSite(expr); | 2121 RecordJSReturnSite(expr); |
2075 // Restore context register. | 2122 // Restore context register. |
2076 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2123 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
2077 | 2124 |
2078 decrement_stack_height(arg_count + 1); | 2125 decrement_stack_height(arg_count + 1); |
2079 context()->DropAndPlug(1, eax); | 2126 context()->DropAndPlug(1, eax); |
2080 } | 2127 } |
2081 | 2128 |
2082 | 2129 |
2083 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, | 2130 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2431 __ LoadInstanceDescriptors(ebx, ebx); | 2478 __ LoadInstanceDescriptors(ebx, ebx); |
2432 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); | 2479 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); |
2433 // ebx: descriptor array | 2480 // ebx: descriptor array |
2434 // ecx: length of descriptor array | 2481 // ecx: length of descriptor array |
2435 // Calculate the end of the descriptor array. | 2482 // Calculate the end of the descriptor array. |
2436 STATIC_ASSERT(kSmiTag == 0); | 2483 STATIC_ASSERT(kSmiTag == 0); |
2437 STATIC_ASSERT(kSmiTagSize == 1); | 2484 STATIC_ASSERT(kSmiTagSize == 1); |
2438 STATIC_ASSERT(kPointerSize == 4); | 2485 STATIC_ASSERT(kPointerSize == 4); |
2439 __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); | 2486 __ lea(ecx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); |
2440 // Calculate location of the first key name. | 2487 // Calculate location of the first key name. |
2441 __ add(Operand(ebx), | 2488 __ add(ebx, |
2442 Immediate(FixedArray::kHeaderSize + | 2489 Immediate(FixedArray::kHeaderSize + |
2443 DescriptorArray::kFirstIndex * kPointerSize)); | 2490 DescriptorArray::kFirstIndex * kPointerSize)); |
2444 // Loop through all the keys in the descriptor array. If one of these is the | 2491 // Loop through all the keys in the descriptor array. If one of these is the |
2445 // symbol valueOf the result is false. | 2492 // symbol valueOf the result is false. |
2446 Label entry, loop; | 2493 Label entry, loop; |
2447 __ jmp(&entry); | 2494 __ jmp(&entry); |
2448 __ bind(&loop); | 2495 __ bind(&loop); |
2449 __ mov(edx, FieldOperand(ebx, 0)); | 2496 __ mov(edx, FieldOperand(ebx, 0)); |
2450 __ cmp(edx, FACTORY->value_of_symbol()); | 2497 __ cmp(edx, FACTORY->value_of_symbol()); |
2451 __ j(equal, if_false); | 2498 __ j(equal, if_false); |
2452 __ add(Operand(ebx), Immediate(kPointerSize)); | 2499 __ add(ebx, Immediate(kPointerSize)); |
2453 __ bind(&entry); | 2500 __ bind(&entry); |
2454 __ cmp(ebx, Operand(ecx)); | 2501 __ cmp(ebx, ecx); |
2455 __ j(not_equal, &loop); | 2502 __ j(not_equal, &loop); |
2456 | 2503 |
2457 // Reload map as register ebx was used as temporary above. | 2504 // Reload map as register ebx was used as temporary above. |
2458 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 2505 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
2459 | 2506 |
2460 // If a valueOf property is not found on the object check that it's | 2507 // If a valueOf property is not found on the object check that it's |
2461 // prototype is the un-modified String prototype. If not result is false. | 2508 // prototype is the un-modified String prototype. If not result is false. |
2462 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); | 2509 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); |
2463 __ JumpIfSmi(ecx, if_false); | 2510 __ JumpIfSmi(ecx, if_false); |
2464 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); | 2511 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2584 | 2631 |
2585 Label materialize_true, materialize_false; | 2632 Label materialize_true, materialize_false; |
2586 Label* if_true = NULL; | 2633 Label* if_true = NULL; |
2587 Label* if_false = NULL; | 2634 Label* if_false = NULL; |
2588 Label* fall_through = NULL; | 2635 Label* fall_through = NULL; |
2589 context()->PrepareTest(&materialize_true, &materialize_false, | 2636 context()->PrepareTest(&materialize_true, &materialize_false, |
2590 &if_true, &if_false, &fall_through); | 2637 &if_true, &if_false, &fall_through); |
2591 | 2638 |
2592 __ pop(ebx); | 2639 __ pop(ebx); |
2593 decrement_stack_height(); | 2640 decrement_stack_height(); |
2594 __ cmp(eax, Operand(ebx)); | 2641 __ cmp(eax, ebx); |
2595 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2642 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2596 Split(equal, if_true, if_false, fall_through); | 2643 Split(equal, if_true, if_false, fall_through); |
2597 | 2644 |
2598 context()->Plug(if_true, if_false); | 2645 context()->Plug(if_true, if_false); |
2599 } | 2646 } |
2600 | 2647 |
2601 | 2648 |
2602 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2649 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
2603 ASSERT(args->length() == 1); | 2650 ASSERT(args->length() == 1); |
2604 | 2651 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2640 ASSERT(args->length() == 1); | 2687 ASSERT(args->length() == 1); |
2641 Label done, null, function, non_function_constructor; | 2688 Label done, null, function, non_function_constructor; |
2642 | 2689 |
2643 VisitForAccumulatorValue(args->at(0)); | 2690 VisitForAccumulatorValue(args->at(0)); |
2644 | 2691 |
2645 // If the object is a smi, we return null. | 2692 // If the object is a smi, we return null. |
2646 __ JumpIfSmi(eax, &null); | 2693 __ JumpIfSmi(eax, &null); |
2647 | 2694 |
2648 // Check that the object is a JS object but take special care of JS | 2695 // Check that the object is a JS object but take special care of JS |
2649 // functions to make sure they have 'Function' as their class. | 2696 // functions to make sure they have 'Function' as their class. |
| 2697 // Assume that there are only two callable types, and one of them is at |
| 2698 // either end of the type range for JS object types. Saves extra comparisons. |
| 2699 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
2650 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax); | 2700 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax); |
2651 // Map is now in eax. | 2701 // Map is now in eax. |
2652 __ j(below, &null); | 2702 __ j(below, &null); |
| 2703 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == |
| 2704 FIRST_SPEC_OBJECT_TYPE + 1); |
| 2705 __ j(equal, &function); |
2653 | 2706 |
2654 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and | 2707 __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE); |
2655 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after | 2708 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == |
2656 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. | 2709 LAST_SPEC_OBJECT_TYPE - 1); |
2657 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); | 2710 __ j(equal, &function); |
2658 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == | 2711 // Assume that there is no larger type. |
2659 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); | 2712 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); |
2660 __ CmpInstanceType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE); | |
2661 __ j(above_equal, &function); | |
2662 | 2713 |
2663 // Check if the constructor in the map is a function. | 2714 // Check if the constructor in the map is a JS function. |
2664 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset)); | 2715 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset)); |
2665 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 2716 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
2666 __ j(not_equal, &non_function_constructor); | 2717 __ j(not_equal, &non_function_constructor); |
2667 | 2718 |
2668 // eax now contains the constructor function. Grab the | 2719 // eax now contains the constructor function. Grab the |
2669 // instance class name from there. | 2720 // instance class name from there. |
2670 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); | 2721 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); |
2671 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); | 2722 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); |
2672 __ jmp(&done); | 2723 __ jmp(&done); |
2673 | 2724 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2734 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), | 2785 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), |
2735 1); | 2786 1); |
2736 | 2787 |
2737 // Convert 32 random bits in eax to 0.(32 random bits) in a double | 2788 // Convert 32 random bits in eax to 0.(32 random bits) in a double |
2738 // by computing: | 2789 // by computing: |
2739 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). | 2790 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
2740 // This is implemented on both SSE2 and FPU. | 2791 // This is implemented on both SSE2 and FPU. |
2741 if (CpuFeatures::IsSupported(SSE2)) { | 2792 if (CpuFeatures::IsSupported(SSE2)) { |
2742 CpuFeatures::Scope fscope(SSE2); | 2793 CpuFeatures::Scope fscope(SSE2); |
2743 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. | 2794 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
2744 __ movd(xmm1, Operand(ebx)); | 2795 __ movd(xmm1, ebx); |
2745 __ movd(xmm0, Operand(eax)); | 2796 __ movd(xmm0, eax); |
2746 __ cvtss2sd(xmm1, xmm1); | 2797 __ cvtss2sd(xmm1, xmm1); |
2747 __ xorps(xmm0, xmm1); | 2798 __ xorps(xmm0, xmm1); |
2748 __ subsd(xmm0, xmm1); | 2799 __ subsd(xmm0, xmm1); |
2749 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); | 2800 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); |
2750 } else { | 2801 } else { |
2751 // 0x4130000000000000 is 1.0 x 2^20 as a double. | 2802 // 0x4130000000000000 is 1.0 x 2^20 as a double. |
2752 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset), | 2803 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset), |
2753 Immediate(0x41300000)); | 2804 Immediate(0x41300000)); |
2754 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax); | 2805 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax); |
2755 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset)); | 2806 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset)); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2836 Label done; | 2887 Label done; |
2837 // If the object is a smi, return the value. | 2888 // If the object is a smi, return the value. |
2838 __ JumpIfSmi(ebx, &done, Label::kNear); | 2889 __ JumpIfSmi(ebx, &done, Label::kNear); |
2839 | 2890 |
2840 // If the object is not a value type, return the value. | 2891 // If the object is not a value type, return the value. |
2841 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx); | 2892 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx); |
2842 __ j(not_equal, &done, Label::kNear); | 2893 __ j(not_equal, &done, Label::kNear); |
2843 | 2894 |
2844 // Store the value. | 2895 // Store the value. |
2845 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); | 2896 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); |
| 2897 |
2846 // Update the write barrier. Save the value as it will be | 2898 // Update the write barrier. Save the value as it will be |
2847 // overwritten by the write barrier code and is needed afterward. | 2899 // overwritten by the write barrier code and is needed afterward. |
2848 __ mov(edx, eax); | 2900 __ mov(edx, eax); |
2849 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx); | 2901 __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs); |
2850 | 2902 |
2851 __ bind(&done); | 2903 __ bind(&done); |
2852 context()->Plug(eax); | 2904 context()->Plug(eax); |
2853 } | 2905 } |
2854 | 2906 |
2855 | 2907 |
2856 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { | 2908 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { |
2857 ASSERT_EQ(args->length(), 1); | 2909 ASSERT_EQ(args->length(), 1); |
2858 | 2910 |
2859 // Load the argument on the stack and call the stub. | 2911 // Load the argument on the stack and call the stub. |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3112 // Check the object's elements are in fast case and writable. | 3164 // Check the object's elements are in fast case and writable. |
3113 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); | 3165 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); |
3114 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), | 3166 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), |
3115 Immediate(isolate()->factory()->fixed_array_map())); | 3167 Immediate(isolate()->factory()->fixed_array_map())); |
3116 __ j(not_equal, &slow_case); | 3168 __ j(not_equal, &slow_case); |
3117 | 3169 |
3118 // Check that both indices are smis. | 3170 // Check that both indices are smis. |
3119 __ mov(index_1, Operand(esp, 1 * kPointerSize)); | 3171 __ mov(index_1, Operand(esp, 1 * kPointerSize)); |
3120 __ mov(index_2, Operand(esp, 0)); | 3172 __ mov(index_2, Operand(esp, 0)); |
3121 __ mov(temp, index_1); | 3173 __ mov(temp, index_1); |
3122 __ or_(temp, Operand(index_2)); | 3174 __ or_(temp, index_2); |
3123 __ JumpIfNotSmi(temp, &slow_case); | 3175 __ JumpIfNotSmi(temp, &slow_case); |
3124 | 3176 |
3125 // Check that both indices are valid. | 3177 // Check that both indices are valid. |
3126 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset)); | 3178 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset)); |
3127 __ cmp(temp, Operand(index_1)); | 3179 __ cmp(temp, index_1); |
3128 __ j(below_equal, &slow_case); | 3180 __ j(below_equal, &slow_case); |
3129 __ cmp(temp, Operand(index_2)); | 3181 __ cmp(temp, index_2); |
3130 __ j(below_equal, &slow_case); | 3182 __ j(below_equal, &slow_case); |
3131 | 3183 |
3132 // Bring addresses into index1 and index2. | 3184 // Bring addresses into index1 and index2. |
3133 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1)); | 3185 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1)); |
3134 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2)); | 3186 __ lea(index_2, CodeGenerator::FixedArrayElementOperand(elements, index_2)); |
3135 | 3187 |
3136 // Swap elements. Use object and temp as scratch registers. | 3188 // Swap elements. Use object and temp as scratch registers. |
3137 __ mov(object, Operand(index_1, 0)); | 3189 __ mov(object, Operand(index_1, 0)); |
3138 __ mov(temp, Operand(index_2, 0)); | 3190 __ mov(temp, Operand(index_2, 0)); |
3139 __ mov(Operand(index_2, 0), object); | 3191 __ mov(Operand(index_2, 0), object); |
3140 __ mov(Operand(index_1, 0), temp); | 3192 __ mov(Operand(index_1, 0), temp); |
3141 | 3193 |
3142 Label new_space; | 3194 Label no_remembered_set; |
3143 __ InNewSpace(elements, temp, equal, &new_space); | 3195 __ CheckPageFlag(elements, |
| 3196 temp, |
| 3197 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
| 3198 not_zero, |
| 3199 &no_remembered_set, |
| 3200 Label::kNear); |
| 3201 // Possible optimization: do a check that both values are Smis |
| 3202 // (or them and test against Smi mask.) |
3144 | 3203 |
3145 __ mov(object, elements); | 3204 // We are swapping two objects in an array and the incremental marker never |
3146 __ RecordWriteHelper(object, index_1, temp); | 3205 // pauses in the middle of scanning a single object. Therefore the |
3147 __ RecordWriteHelper(elements, index_2, temp); | 3206 // incremental marker is not disturbed, so we don't need to call the |
| 3207 // RecordWrite stub that notifies the incremental marker. |
| 3208 __ RememberedSetHelper(elements, |
| 3209 index_1, |
| 3210 temp, |
| 3211 kDontSaveFPRegs, |
| 3212 MacroAssembler::kFallThroughAtEnd); |
| 3213 __ RememberedSetHelper(elements, |
| 3214 index_2, |
| 3215 temp, |
| 3216 kDontSaveFPRegs, |
| 3217 MacroAssembler::kFallThroughAtEnd); |
3148 | 3218 |
3149 __ bind(&new_space); | 3219 __ bind(&no_remembered_set); |
| 3220 |
3150 // We are done. Drop elements from the stack, and return undefined. | 3221 // We are done. Drop elements from the stack, and return undefined. |
3151 __ add(Operand(esp), Immediate(3 * kPointerSize)); | 3222 __ add(esp, Immediate(3 * kPointerSize)); |
3152 __ mov(eax, isolate()->factory()->undefined_value()); | 3223 __ mov(eax, isolate()->factory()->undefined_value()); |
3153 __ jmp(&done); | 3224 __ jmp(&done); |
3154 | 3225 |
3155 __ bind(&slow_case); | 3226 __ bind(&slow_case); |
3156 __ CallRuntime(Runtime::kSwapElements, 3); | 3227 __ CallRuntime(Runtime::kSwapElements, 3); |
3157 | 3228 |
3158 __ bind(&done); | 3229 __ bind(&done); |
3159 decrement_stack_height(3); | 3230 decrement_stack_height(3); |
3160 context()->Plug(eax); | 3231 context()->Plug(eax); |
3161 } | 3232 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3214 | 3285 |
3215 Register right = eax; | 3286 Register right = eax; |
3216 Register left = ebx; | 3287 Register left = ebx; |
3217 Register tmp = ecx; | 3288 Register tmp = ecx; |
3218 | 3289 |
3219 VisitForStackValue(args->at(0)); | 3290 VisitForStackValue(args->at(0)); |
3220 VisitForAccumulatorValue(args->at(1)); | 3291 VisitForAccumulatorValue(args->at(1)); |
3221 __ pop(left); | 3292 __ pop(left); |
3222 | 3293 |
3223 Label done, fail, ok; | 3294 Label done, fail, ok; |
3224 __ cmp(left, Operand(right)); | 3295 __ cmp(left, right); |
3225 __ j(equal, &ok); | 3296 __ j(equal, &ok); |
3226 // Fail if either is a non-HeapObject. | 3297 // Fail if either is a non-HeapObject. |
3227 __ mov(tmp, left); | 3298 __ mov(tmp, left); |
3228 __ and_(Operand(tmp), right); | 3299 __ and_(tmp, right); |
3229 __ JumpIfSmi(tmp, &fail); | 3300 __ JumpIfSmi(tmp, &fail); |
3230 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); | 3301 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); |
3231 __ CmpInstanceType(tmp, JS_REGEXP_TYPE); | 3302 __ CmpInstanceType(tmp, JS_REGEXP_TYPE); |
3232 __ j(not_equal, &fail); | 3303 __ j(not_equal, &fail); |
3233 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); | 3304 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); |
3234 __ j(not_equal, &fail); | 3305 __ j(not_equal, &fail); |
3235 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); | 3306 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); |
3236 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); | 3307 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); |
3237 __ j(equal, &ok); | 3308 __ j(equal, &ok); |
3238 __ bind(&fail); | 3309 __ bind(&fail); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3309 | 3380 |
3310 Register scratch = ebx; | 3381 Register scratch = ebx; |
3311 | 3382 |
3312 Register array_length = edi; | 3383 Register array_length = edi; |
3313 Register result_pos = no_reg; // Will be edi. | 3384 Register result_pos = no_reg; // Will be edi. |
3314 | 3385 |
3315 // Separator operand is already pushed. | 3386 // Separator operand is already pushed. |
3316 Operand separator_operand = Operand(esp, 2 * kPointerSize); | 3387 Operand separator_operand = Operand(esp, 2 * kPointerSize); |
3317 Operand result_operand = Operand(esp, 1 * kPointerSize); | 3388 Operand result_operand = Operand(esp, 1 * kPointerSize); |
3318 Operand array_length_operand = Operand(esp, 0); | 3389 Operand array_length_operand = Operand(esp, 0); |
3319 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | 3390 __ sub(esp, Immediate(2 * kPointerSize)); |
3320 __ cld(); | 3391 __ cld(); |
3321 // Check that the array is a JSArray | 3392 // Check that the array is a JSArray |
3322 __ JumpIfSmi(array, &bailout); | 3393 __ JumpIfSmi(array, &bailout); |
3323 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); | 3394 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); |
3324 __ j(not_equal, &bailout); | 3395 __ j(not_equal, &bailout); |
3325 | 3396 |
3326 // Check that the array has fast elements. | 3397 // Check that the array has fast elements. |
3327 __ CheckFastElements(scratch, &bailout); | 3398 __ CheckFastElements(scratch, &bailout); |
3328 | 3399 |
3329 // If the array has length zero, return the empty string. | 3400 // If the array has length zero, return the empty string. |
(...skipping 15 matching lines...) Expand all Loading... |
3345 | 3416 |
3346 | 3417 |
3347 // Check that all array elements are sequential ASCII strings, and | 3418 // Check that all array elements are sequential ASCII strings, and |
3348 // accumulate the sum of their lengths, as a smi-encoded value. | 3419 // accumulate the sum of their lengths, as a smi-encoded value. |
3349 __ Set(index, Immediate(0)); | 3420 __ Set(index, Immediate(0)); |
3350 __ Set(string_length, Immediate(0)); | 3421 __ Set(string_length, Immediate(0)); |
3351 // Loop condition: while (index < length). | 3422 // Loop condition: while (index < length). |
3352 // Live loop registers: index, array_length, string, | 3423 // Live loop registers: index, array_length, string, |
3353 // scratch, string_length, elements. | 3424 // scratch, string_length, elements. |
3354 if (FLAG_debug_code) { | 3425 if (FLAG_debug_code) { |
3355 __ cmp(index, Operand(array_length)); | 3426 __ cmp(index, array_length); |
3356 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin"); | 3427 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin"); |
3357 } | 3428 } |
3358 __ bind(&loop); | 3429 __ bind(&loop); |
3359 __ mov(string, FieldOperand(elements, | 3430 __ mov(string, FieldOperand(elements, |
3360 index, | 3431 index, |
3361 times_pointer_size, | 3432 times_pointer_size, |
3362 FixedArray::kHeaderSize)); | 3433 FixedArray::kHeaderSize)); |
3363 __ JumpIfSmi(string, &bailout); | 3434 __ JumpIfSmi(string, &bailout); |
3364 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); | 3435 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
3365 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3436 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
3366 __ and_(scratch, Immediate( | 3437 __ and_(scratch, Immediate( |
3367 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3438 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
3368 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 3439 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
3369 __ j(not_equal, &bailout); | 3440 __ j(not_equal, &bailout); |
3370 __ add(string_length, | 3441 __ add(string_length, |
3371 FieldOperand(string, SeqAsciiString::kLengthOffset)); | 3442 FieldOperand(string, SeqAsciiString::kLengthOffset)); |
3372 __ j(overflow, &bailout); | 3443 __ j(overflow, &bailout); |
3373 __ add(Operand(index), Immediate(1)); | 3444 __ add(index, Immediate(1)); |
3374 __ cmp(index, Operand(array_length)); | 3445 __ cmp(index, array_length); |
3375 __ j(less, &loop); | 3446 __ j(less, &loop); |
3376 | 3447 |
3377 // If array_length is 1, return elements[0], a string. | 3448 // If array_length is 1, return elements[0], a string. |
3378 __ cmp(array_length, 1); | 3449 __ cmp(array_length, 1); |
3379 __ j(not_equal, ¬_size_one_array); | 3450 __ j(not_equal, ¬_size_one_array); |
3380 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize)); | 3451 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize)); |
3381 __ mov(result_operand, scratch); | 3452 __ mov(result_operand, scratch); |
3382 __ jmp(&done); | 3453 __ jmp(&done); |
3383 | 3454 |
3384 __ bind(¬_size_one_array); | 3455 __ bind(¬_size_one_array); |
(...skipping 13 matching lines...) Expand all Loading... |
3398 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3469 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
3399 __ and_(scratch, Immediate( | 3470 __ and_(scratch, Immediate( |
3400 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3471 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
3401 __ cmp(scratch, ASCII_STRING_TYPE); | 3472 __ cmp(scratch, ASCII_STRING_TYPE); |
3402 __ j(not_equal, &bailout); | 3473 __ j(not_equal, &bailout); |
3403 | 3474 |
3404 // Add (separator length times array_length) - separator length | 3475 // Add (separator length times array_length) - separator length |
3405 // to string_length. | 3476 // to string_length. |
3406 __ mov(scratch, separator_operand); | 3477 __ mov(scratch, separator_operand); |
3407 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); | 3478 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); |
3408 __ sub(string_length, Operand(scratch)); // May be negative, temporarily. | 3479 __ sub(string_length, scratch); // May be negative, temporarily. |
3409 __ imul(scratch, array_length_operand); | 3480 __ imul(scratch, array_length_operand); |
3410 __ j(overflow, &bailout); | 3481 __ j(overflow, &bailout); |
3411 __ add(string_length, Operand(scratch)); | 3482 __ add(string_length, scratch); |
3412 __ j(overflow, &bailout); | 3483 __ j(overflow, &bailout); |
3413 | 3484 |
3414 __ shr(string_length, 1); | 3485 __ shr(string_length, 1); |
3415 // Live registers and stack values: | 3486 // Live registers and stack values: |
3416 // string_length | 3487 // string_length |
3417 // elements | 3488 // elements |
3418 __ AllocateAsciiString(result_pos, string_length, scratch, | 3489 __ AllocateAsciiString(result_pos, string_length, scratch, |
3419 index, string, &bailout); | 3490 index, string, &bailout); |
3420 __ mov(result_operand, result_pos); | 3491 __ mov(result_operand, result_pos); |
3421 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize)); | 3492 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize)); |
(...skipping 20 matching lines...) Expand all Loading... |
3442 // Get string = array[index]. | 3513 // Get string = array[index]. |
3443 __ mov(string, FieldOperand(elements, index, | 3514 __ mov(string, FieldOperand(elements, index, |
3444 times_pointer_size, | 3515 times_pointer_size, |
3445 FixedArray::kHeaderSize)); | 3516 FixedArray::kHeaderSize)); |
3446 __ mov(string_length, | 3517 __ mov(string_length, |
3447 FieldOperand(string, String::kLengthOffset)); | 3518 FieldOperand(string, String::kLengthOffset)); |
3448 __ shr(string_length, 1); | 3519 __ shr(string_length, 1); |
3449 __ lea(string, | 3520 __ lea(string, |
3450 FieldOperand(string, SeqAsciiString::kHeaderSize)); | 3521 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
3451 __ CopyBytes(string, result_pos, string_length, scratch); | 3522 __ CopyBytes(string, result_pos, string_length, scratch); |
3452 __ add(Operand(index), Immediate(1)); | 3523 __ add(index, Immediate(1)); |
3453 __ bind(&loop_1_condition); | 3524 __ bind(&loop_1_condition); |
3454 __ cmp(index, array_length_operand); | 3525 __ cmp(index, array_length_operand); |
3455 __ j(less, &loop_1); // End while (index < length). | 3526 __ j(less, &loop_1); // End while (index < length). |
3456 __ jmp(&done); | 3527 __ jmp(&done); |
3457 | 3528 |
3458 | 3529 |
3459 | 3530 |
3460 // One-character separator case | 3531 // One-character separator case |
3461 __ bind(&one_char_separator); | 3532 __ bind(&one_char_separator); |
3462 // Replace separator with its ascii character value. | 3533 // Replace separator with its ascii character value. |
(...skipping 20 matching lines...) Expand all Loading... |
3483 // Get string = array[index]. | 3554 // Get string = array[index]. |
3484 __ mov(string, FieldOperand(elements, index, | 3555 __ mov(string, FieldOperand(elements, index, |
3485 times_pointer_size, | 3556 times_pointer_size, |
3486 FixedArray::kHeaderSize)); | 3557 FixedArray::kHeaderSize)); |
3487 __ mov(string_length, | 3558 __ mov(string_length, |
3488 FieldOperand(string, String::kLengthOffset)); | 3559 FieldOperand(string, String::kLengthOffset)); |
3489 __ shr(string_length, 1); | 3560 __ shr(string_length, 1); |
3490 __ lea(string, | 3561 __ lea(string, |
3491 FieldOperand(string, SeqAsciiString::kHeaderSize)); | 3562 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
3492 __ CopyBytes(string, result_pos, string_length, scratch); | 3563 __ CopyBytes(string, result_pos, string_length, scratch); |
3493 __ add(Operand(index), Immediate(1)); | 3564 __ add(index, Immediate(1)); |
3494 | 3565 |
3495 __ cmp(index, array_length_operand); | 3566 __ cmp(index, array_length_operand); |
3496 __ j(less, &loop_2); // End while (index < length). | 3567 __ j(less, &loop_2); // End while (index < length). |
3497 __ jmp(&done); | 3568 __ jmp(&done); |
3498 | 3569 |
3499 | 3570 |
3500 // Long separator case (separator is more than one character). | 3571 // Long separator case (separator is more than one character). |
3501 __ bind(&long_separator); | 3572 __ bind(&long_separator); |
3502 | 3573 |
3503 __ Set(index, Immediate(0)); | 3574 __ Set(index, Immediate(0)); |
(...skipping 20 matching lines...) Expand all Loading... |
3524 // Get string = array[index]. | 3595 // Get string = array[index]. |
3525 __ mov(string, FieldOperand(elements, index, | 3596 __ mov(string, FieldOperand(elements, index, |
3526 times_pointer_size, | 3597 times_pointer_size, |
3527 FixedArray::kHeaderSize)); | 3598 FixedArray::kHeaderSize)); |
3528 __ mov(string_length, | 3599 __ mov(string_length, |
3529 FieldOperand(string, String::kLengthOffset)); | 3600 FieldOperand(string, String::kLengthOffset)); |
3530 __ shr(string_length, 1); | 3601 __ shr(string_length, 1); |
3531 __ lea(string, | 3602 __ lea(string, |
3532 FieldOperand(string, SeqAsciiString::kHeaderSize)); | 3603 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
3533 __ CopyBytes(string, result_pos, string_length, scratch); | 3604 __ CopyBytes(string, result_pos, string_length, scratch); |
3534 __ add(Operand(index), Immediate(1)); | 3605 __ add(index, Immediate(1)); |
3535 | 3606 |
3536 __ cmp(index, array_length_operand); | 3607 __ cmp(index, array_length_operand); |
3537 __ j(less, &loop_3); // End while (index < length). | 3608 __ j(less, &loop_3); // End while (index < length). |
3538 __ jmp(&done); | 3609 __ jmp(&done); |
3539 | 3610 |
3540 | 3611 |
3541 __ bind(&bailout); | 3612 __ bind(&bailout); |
3542 __ mov(result_operand, isolate()->factory()->undefined_value()); | 3613 __ mov(result_operand, isolate()->factory()->undefined_value()); |
3543 __ bind(&done); | 3614 __ bind(&done); |
3544 __ mov(eax, result_operand); | 3615 __ mov(eax, result_operand); |
3545 // Drop temp values from the stack, and restore context register. | 3616 // Drop temp values from the stack, and restore context register. |
3546 __ add(Operand(esp), Immediate(3 * kPointerSize)); | 3617 __ add(esp, Immediate(3 * kPointerSize)); |
3547 | 3618 |
3548 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3619 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
3549 decrement_stack_height(); | 3620 decrement_stack_height(); |
3550 context()->Plug(eax); | 3621 context()->Plug(eax); |
3551 } | 3622 } |
3552 | 3623 |
3553 | 3624 |
3554 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 3625 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
3555 Handle<String> name = expr->name(); | 3626 Handle<String> name = expr->name(); |
3556 if (name->length() > 0 && name->Get(0) == '_') { | 3627 if (name->length() > 0 && name->Get(0) == '_') { |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3816 } | 3887 } |
3817 } | 3888 } |
3818 } | 3889 } |
3819 | 3890 |
3820 // Inline smi case if we are in a loop. | 3891 // Inline smi case if we are in a loop. |
3821 Label done, stub_call; | 3892 Label done, stub_call; |
3822 JumpPatchSite patch_site(masm_); | 3893 JumpPatchSite patch_site(masm_); |
3823 | 3894 |
3824 if (ShouldInlineSmiCase(expr->op())) { | 3895 if (ShouldInlineSmiCase(expr->op())) { |
3825 if (expr->op() == Token::INC) { | 3896 if (expr->op() == Token::INC) { |
3826 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 3897 __ add(eax, Immediate(Smi::FromInt(1))); |
3827 } else { | 3898 } else { |
3828 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | 3899 __ sub(eax, Immediate(Smi::FromInt(1))); |
3829 } | 3900 } |
3830 __ j(overflow, &stub_call, Label::kNear); | 3901 __ j(overflow, &stub_call, Label::kNear); |
3831 // We could eliminate this smi check if we split the code at | 3902 // We could eliminate this smi check if we split the code at |
3832 // the first smi check before calling ToNumber. | 3903 // the first smi check before calling ToNumber. |
3833 patch_site.EmitJumpIfSmi(eax, &done, Label::kNear); | 3904 patch_site.EmitJumpIfSmi(eax, &done, Label::kNear); |
3834 | 3905 |
3835 __ bind(&stub_call); | 3906 __ bind(&stub_call); |
3836 // Call stub. Undo operation first. | 3907 // Call stub. Undo operation first. |
3837 if (expr->op() == Token::INC) { | 3908 if (expr->op() == Token::INC) { |
3838 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | 3909 __ sub(eax, Immediate(Smi::FromInt(1))); |
3839 } else { | 3910 } else { |
3840 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 3911 __ add(eax, Immediate(Smi::FromInt(1))); |
3841 } | 3912 } |
3842 } | 3913 } |
3843 | 3914 |
3844 // Record position before stub call. | 3915 // Record position before stub call. |
3845 SetSourcePosition(expr->position()); | 3916 SetSourcePosition(expr->position()); |
3846 | 3917 |
3847 // Call stub for +1/-1. | 3918 // Call stub for +1/-1. |
3848 __ mov(edx, eax); | 3919 __ mov(edx, eax); |
3849 __ mov(eax, Immediate(Smi::FromInt(1))); | 3920 __ mov(eax, Immediate(Smi::FromInt(1))); |
3850 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); | 3921 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3949 | 4020 |
3950 context()->Plug(eax); | 4021 context()->Plug(eax); |
3951 } else { | 4022 } else { |
3952 // This expression cannot throw a reference error at the top level. | 4023 // This expression cannot throw a reference error at the top level. |
3953 VisitInCurrentContext(expr); | 4024 VisitInCurrentContext(expr); |
3954 } | 4025 } |
3955 } | 4026 } |
3956 | 4027 |
3957 | 4028 |
3958 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, | 4029 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, |
3959 Handle<String> check, | 4030 Handle<String> check) { |
3960 Label* if_true, | 4031 Label materialize_true, materialize_false; |
3961 Label* if_false, | 4032 Label* if_true = NULL; |
3962 Label* fall_through) { | 4033 Label* if_false = NULL; |
| 4034 Label* fall_through = NULL; |
| 4035 context()->PrepareTest(&materialize_true, &materialize_false, |
| 4036 &if_true, &if_false, &fall_through); |
| 4037 |
3963 { AccumulatorValueContext context(this); | 4038 { AccumulatorValueContext context(this); |
3964 VisitForTypeofValue(expr); | 4039 VisitForTypeofValue(expr); |
3965 } | 4040 } |
3966 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4041 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3967 | 4042 |
3968 if (check->Equals(isolate()->heap()->number_symbol())) { | 4043 if (check->Equals(isolate()->heap()->number_symbol())) { |
3969 __ JumpIfSmi(eax, if_true); | 4044 __ JumpIfSmi(eax, if_true); |
3970 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 4045 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
3971 isolate()->factory()->heap_number_map()); | 4046 isolate()->factory()->heap_number_map()); |
3972 Split(equal, if_true, if_false, fall_through); | 4047 Split(equal, if_true, if_false, fall_through); |
(...skipping 18 matching lines...) Expand all Loading... |
3991 __ cmp(eax, isolate()->factory()->undefined_value()); | 4066 __ cmp(eax, isolate()->factory()->undefined_value()); |
3992 __ j(equal, if_true); | 4067 __ j(equal, if_true); |
3993 __ JumpIfSmi(eax, if_false); | 4068 __ JumpIfSmi(eax, if_false); |
3994 // Check for undetectable objects => true. | 4069 // Check for undetectable objects => true. |
3995 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 4070 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
3996 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 4071 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
3997 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 4072 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
3998 Split(not_zero, if_true, if_false, fall_through); | 4073 Split(not_zero, if_true, if_false, fall_through); |
3999 } else if (check->Equals(isolate()->heap()->function_symbol())) { | 4074 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
4000 __ JumpIfSmi(eax, if_false); | 4075 __ JumpIfSmi(eax, if_false); |
4001 __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx); | 4076 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
4002 Split(above_equal, if_true, if_false, fall_through); | 4077 __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx); |
| 4078 __ j(equal, if_true); |
| 4079 __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE); |
| 4080 Split(equal, if_true, if_false, fall_through); |
4003 } else if (check->Equals(isolate()->heap()->object_symbol())) { | 4081 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
4004 __ JumpIfSmi(eax, if_false); | 4082 __ JumpIfSmi(eax, if_false); |
4005 if (!FLAG_harmony_typeof) { | 4083 if (!FLAG_harmony_typeof) { |
4006 __ cmp(eax, isolate()->factory()->null_value()); | 4084 __ cmp(eax, isolate()->factory()->null_value()); |
4007 __ j(equal, if_true); | 4085 __ j(equal, if_true); |
4008 } | 4086 } |
4009 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx); | 4087 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx); |
4010 __ j(below, if_false); | 4088 __ j(below, if_false); |
4011 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 4089 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
4012 __ j(above, if_false); | 4090 __ j(above, if_false); |
4013 // Check for undetectable objects => false. | 4091 // Check for undetectable objects => false. |
4014 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), | 4092 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
4015 1 << Map::kIsUndetectable); | 4093 1 << Map::kIsUndetectable); |
4016 Split(zero, if_true, if_false, fall_through); | 4094 Split(zero, if_true, if_false, fall_through); |
4017 } else { | 4095 } else { |
4018 if (if_false != fall_through) __ jmp(if_false); | 4096 if (if_false != fall_through) __ jmp(if_false); |
4019 } | 4097 } |
4020 } | 4098 context()->Plug(if_true, if_false); |
4021 | |
4022 | |
4023 void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr, | |
4024 Label* if_true, | |
4025 Label* if_false, | |
4026 Label* fall_through) { | |
4027 VisitForAccumulatorValue(expr); | |
4028 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | |
4029 | |
4030 __ cmp(eax, isolate()->factory()->undefined_value()); | |
4031 Split(equal, if_true, if_false, fall_through); | |
4032 } | 4099 } |
4033 | 4100 |
4034 | 4101 |
4035 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 4102 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
4036 Comment cmnt(masm_, "[ CompareOperation"); | 4103 Comment cmnt(masm_, "[ CompareOperation"); |
4037 SetSourcePosition(expr->position()); | 4104 SetSourcePosition(expr->position()); |
4038 | 4105 |
| 4106 // First we try a fast inlined version of the compare when one of |
| 4107 // the operands is a literal. |
| 4108 if (TryLiteralCompare(expr)) return; |
| 4109 |
4039 // Always perform the comparison for its control flow. Pack the result | 4110 // Always perform the comparison for its control flow. Pack the result |
4040 // into the expression's context after the comparison is performed. | 4111 // into the expression's context after the comparison is performed. |
4041 | |
4042 Label materialize_true, materialize_false; | 4112 Label materialize_true, materialize_false; |
4043 Label* if_true = NULL; | 4113 Label* if_true = NULL; |
4044 Label* if_false = NULL; | 4114 Label* if_false = NULL; |
4045 Label* fall_through = NULL; | 4115 Label* fall_through = NULL; |
4046 context()->PrepareTest(&materialize_true, &materialize_false, | 4116 context()->PrepareTest(&materialize_true, &materialize_false, |
4047 &if_true, &if_false, &fall_through); | 4117 &if_true, &if_false, &fall_through); |
4048 | 4118 |
4049 // First we try a fast inlined version of the compare when one of | |
4050 // the operands is a literal. | |
4051 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) { | |
4052 context()->Plug(if_true, if_false); | |
4053 return; | |
4054 } | |
4055 | |
4056 Token::Value op = expr->op(); | 4119 Token::Value op = expr->op(); |
4057 VisitForStackValue(expr->left()); | 4120 VisitForStackValue(expr->left()); |
4058 switch (expr->op()) { | 4121 switch (op) { |
4059 case Token::IN: | 4122 case Token::IN: |
4060 VisitForStackValue(expr->right()); | 4123 VisitForStackValue(expr->right()); |
4061 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 4124 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
4062 decrement_stack_height(2); | 4125 decrement_stack_height(2); |
4063 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 4126 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
4064 __ cmp(eax, isolate()->factory()->true_value()); | 4127 __ cmp(eax, isolate()->factory()->true_value()); |
4065 Split(equal, if_true, if_false, fall_through); | 4128 Split(equal, if_true, if_false, fall_through); |
4066 break; | 4129 break; |
4067 | 4130 |
4068 case Token::INSTANCEOF: { | 4131 case Token::INSTANCEOF: { |
4069 VisitForStackValue(expr->right()); | 4132 VisitForStackValue(expr->right()); |
4070 InstanceofStub stub(InstanceofStub::kNoFlags); | 4133 InstanceofStub stub(InstanceofStub::kNoFlags); |
4071 __ CallStub(&stub); | 4134 __ CallStub(&stub); |
4072 decrement_stack_height(2); | 4135 decrement_stack_height(2); |
4073 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4136 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
4074 __ test(eax, Operand(eax)); | 4137 __ test(eax, eax); |
4075 // The stub returns 0 for true. | 4138 // The stub returns 0 for true. |
4076 Split(zero, if_true, if_false, fall_through); | 4139 Split(zero, if_true, if_false, fall_through); |
4077 break; | 4140 break; |
4078 } | 4141 } |
4079 | 4142 |
4080 default: { | 4143 default: { |
4081 VisitForAccumulatorValue(expr->right()); | 4144 VisitForAccumulatorValue(expr->right()); |
4082 Condition cc = no_condition; | 4145 Condition cc = no_condition; |
4083 bool strict = false; | |
4084 switch (op) { | 4146 switch (op) { |
4085 case Token::EQ_STRICT: | 4147 case Token::EQ_STRICT: |
4086 strict = true; | |
4087 // Fall through | |
4088 case Token::EQ: | 4148 case Token::EQ: |
4089 cc = equal; | 4149 cc = equal; |
4090 __ pop(edx); | 4150 __ pop(edx); |
4091 break; | 4151 break; |
4092 case Token::LT: | 4152 case Token::LT: |
4093 cc = less; | 4153 cc = less; |
4094 __ pop(edx); | 4154 __ pop(edx); |
4095 break; | 4155 break; |
4096 case Token::GT: | 4156 case Token::GT: |
4097 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 4157 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
(...skipping 15 matching lines...) Expand all Loading... |
4113 case Token::INSTANCEOF: | 4173 case Token::INSTANCEOF: |
4114 default: | 4174 default: |
4115 UNREACHABLE(); | 4175 UNREACHABLE(); |
4116 } | 4176 } |
4117 decrement_stack_height(); | 4177 decrement_stack_height(); |
4118 | 4178 |
4119 bool inline_smi_code = ShouldInlineSmiCase(op); | 4179 bool inline_smi_code = ShouldInlineSmiCase(op); |
4120 JumpPatchSite patch_site(masm_); | 4180 JumpPatchSite patch_site(masm_); |
4121 if (inline_smi_code) { | 4181 if (inline_smi_code) { |
4122 Label slow_case; | 4182 Label slow_case; |
4123 __ mov(ecx, Operand(edx)); | 4183 __ mov(ecx, edx); |
4124 __ or_(ecx, Operand(eax)); | 4184 __ or_(ecx, eax); |
4125 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); | 4185 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); |
4126 __ cmp(edx, Operand(eax)); | 4186 __ cmp(edx, eax); |
4127 Split(cc, if_true, if_false, NULL); | 4187 Split(cc, if_true, if_false, NULL); |
4128 __ bind(&slow_case); | 4188 __ bind(&slow_case); |
4129 } | 4189 } |
4130 | 4190 |
4131 // Record position and call the compare IC. | 4191 // Record position and call the compare IC. |
4132 SetSourcePosition(expr->position()); | 4192 SetSourcePosition(expr->position()); |
4133 Handle<Code> ic = CompareIC::GetUninitialized(op); | 4193 Handle<Code> ic = CompareIC::GetUninitialized(op); |
4134 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); | 4194 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
4135 patch_site.EmitPatchInfo(); | 4195 patch_site.EmitPatchInfo(); |
4136 | 4196 |
4137 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4197 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
4138 __ test(eax, Operand(eax)); | 4198 __ test(eax, eax); |
4139 Split(cc, if_true, if_false, fall_through); | 4199 Split(cc, if_true, if_false, fall_through); |
4140 } | 4200 } |
4141 } | 4201 } |
4142 | 4202 |
4143 // Convert the result of the comparison into one expected for this | 4203 // Convert the result of the comparison into one expected for this |
4144 // expression's context. | 4204 // expression's context. |
4145 context()->Plug(if_true, if_false); | 4205 context()->Plug(if_true, if_false); |
4146 } | 4206 } |
4147 | 4207 |
4148 | 4208 |
4149 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { | 4209 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, |
| 4210 Expression* sub_expr, |
| 4211 NilValue nil) { |
4150 Label materialize_true, materialize_false; | 4212 Label materialize_true, materialize_false; |
4151 Label* if_true = NULL; | 4213 Label* if_true = NULL; |
4152 Label* if_false = NULL; | 4214 Label* if_false = NULL; |
4153 Label* fall_through = NULL; | 4215 Label* fall_through = NULL; |
4154 context()->PrepareTest(&materialize_true, &materialize_false, | 4216 context()->PrepareTest(&materialize_true, &materialize_false, |
4155 &if_true, &if_false, &fall_through); | 4217 &if_true, &if_false, &fall_through); |
4156 | 4218 |
4157 VisitForAccumulatorValue(expr->expression()); | 4219 VisitForAccumulatorValue(sub_expr); |
4158 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4220 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
4159 | 4221 Handle<Object> nil_value = nil == kNullValue ? |
4160 __ cmp(eax, isolate()->factory()->null_value()); | 4222 isolate()->factory()->null_value() : |
4161 if (expr->is_strict()) { | 4223 isolate()->factory()->undefined_value(); |
| 4224 __ cmp(eax, nil_value); |
| 4225 if (expr->op() == Token::EQ_STRICT) { |
4162 Split(equal, if_true, if_false, fall_through); | 4226 Split(equal, if_true, if_false, fall_through); |
4163 } else { | 4227 } else { |
| 4228 Handle<Object> other_nil_value = nil == kNullValue ? |
| 4229 isolate()->factory()->undefined_value() : |
| 4230 isolate()->factory()->null_value(); |
4164 __ j(equal, if_true); | 4231 __ j(equal, if_true); |
4165 __ cmp(eax, isolate()->factory()->undefined_value()); | 4232 __ cmp(eax, other_nil_value); |
4166 __ j(equal, if_true); | 4233 __ j(equal, if_true); |
4167 __ JumpIfSmi(eax, if_false); | 4234 __ JumpIfSmi(eax, if_false); |
4168 // It can be an undetectable object. | 4235 // It can be an undetectable object. |
4169 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 4236 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
4170 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset)); | 4237 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset)); |
4171 __ test(edx, Immediate(1 << Map::kIsUndetectable)); | 4238 __ test(edx, Immediate(1 << Map::kIsUndetectable)); |
4172 Split(not_zero, if_true, if_false, fall_through); | 4239 Split(not_zero, if_true, if_false, fall_through); |
4173 } | 4240 } |
4174 context()->Plug(if_true, if_false); | 4241 context()->Plug(if_true, if_false); |
4175 } | 4242 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4222 } | 4289 } |
4223 | 4290 |
4224 | 4291 |
4225 // ---------------------------------------------------------------------------- | 4292 // ---------------------------------------------------------------------------- |
4226 // Non-local control flow support. | 4293 // Non-local control flow support. |
4227 | 4294 |
4228 void FullCodeGenerator::EnterFinallyBlock() { | 4295 void FullCodeGenerator::EnterFinallyBlock() { |
4229 // Cook return address on top of stack (smi encoded Code* delta) | 4296 // Cook return address on top of stack (smi encoded Code* delta) |
4230 ASSERT(!result_register().is(edx)); | 4297 ASSERT(!result_register().is(edx)); |
4231 __ pop(edx); | 4298 __ pop(edx); |
4232 __ sub(Operand(edx), Immediate(masm_->CodeObject())); | 4299 __ sub(edx, Immediate(masm_->CodeObject())); |
4233 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 4300 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
4234 STATIC_ASSERT(kSmiTag == 0); | 4301 STATIC_ASSERT(kSmiTag == 0); |
4235 __ SmiTag(edx); | 4302 __ SmiTag(edx); |
4236 __ push(edx); | 4303 __ push(edx); |
4237 // Store result register while executing finally block. | 4304 // Store result register while executing finally block. |
4238 __ push(result_register()); | 4305 __ push(result_register()); |
4239 } | 4306 } |
4240 | 4307 |
4241 | 4308 |
4242 void FullCodeGenerator::ExitFinallyBlock() { | 4309 void FullCodeGenerator::ExitFinallyBlock() { |
4243 ASSERT(!result_register().is(edx)); | 4310 ASSERT(!result_register().is(edx)); |
4244 __ pop(result_register()); | 4311 __ pop(result_register()); |
4245 // Uncook return address. | 4312 // Uncook return address. |
4246 __ pop(edx); | 4313 __ pop(edx); |
4247 __ SmiUntag(edx); | 4314 __ SmiUntag(edx); |
4248 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 4315 __ add(edx, Immediate(masm_->CodeObject())); |
4249 __ jmp(Operand(edx)); | 4316 __ jmp(edx); |
4250 } | 4317 } |
4251 | 4318 |
4252 | 4319 |
4253 #undef __ | 4320 #undef __ |
4254 | 4321 |
4255 #define __ ACCESS_MASM(masm()) | 4322 #define __ ACCESS_MASM(masm()) |
4256 | 4323 |
4257 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( | 4324 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( |
4258 int* stack_depth, | 4325 int* stack_depth, |
4259 int* context_length) { | 4326 int* context_length) { |
(...skipping 16 matching lines...) Expand all Loading... |
4276 *context_length = 0; | 4343 *context_length = 0; |
4277 return previous_; | 4344 return previous_; |
4278 } | 4345 } |
4279 | 4346 |
4280 | 4347 |
4281 #undef __ | 4348 #undef __ |
4282 | 4349 |
4283 } } // namespace v8::internal | 4350 } } // namespace v8::internal |
4284 | 4351 |
4285 #endif // V8_TARGET_ARCH_IA32 | 4352 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |