| 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 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 Comment cmnt(masm_, "[ Declarations"); | 247 Comment cmnt(masm_, "[ Declarations"); |
| 248 scope()->VisitIllegalRedeclaration(this); | 248 scope()->VisitIllegalRedeclaration(this); |
| 249 | 249 |
| 250 } else { | 250 } else { |
| 251 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 251 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
| 252 { Comment cmnt(masm_, "[ Declarations"); | 252 { Comment cmnt(masm_, "[ Declarations"); |
| 253 // For named function expressions, declare the function name as a | 253 // For named function expressions, declare the function name as a |
| 254 // constant. | 254 // constant. |
| 255 if (scope()->is_function_scope() && scope()->function() != NULL) { | 255 if (scope()->is_function_scope() && scope()->function() != NULL) { |
| 256 int ignored = 0; | 256 int ignored = 0; |
| 257 EmitDeclaration(scope()->function(), CONST, NULL, &ignored); | 257 VariableProxy* proxy = scope()->function(); |
| 258 ASSERT(proxy->var()->mode() == CONST || |
| 259 proxy->var()->mode() == CONST_HARMONY); |
| 260 EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored); |
| 258 } | 261 } |
| 259 VisitDeclarations(scope()->declarations()); | 262 VisitDeclarations(scope()->declarations()); |
| 260 } | 263 } |
| 261 | 264 |
| 262 { Comment cmnt(masm_, "[ Stack check"); | 265 { Comment cmnt(masm_, "[ Stack check"); |
| 263 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 266 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
| 264 Label ok; | 267 Label ok; |
| 265 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 268 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 266 __ j(above_equal, &ok, Label::kNear); | 269 __ j(above_equal, &ok, Label::kNear); |
| 267 StackCheckStub stub; | 270 StackCheckStub stub; |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 | 680 |
| 678 | 681 |
| 679 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 682 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
| 680 VariableMode mode, | 683 VariableMode mode, |
| 681 FunctionLiteral* function, | 684 FunctionLiteral* function, |
| 682 int* global_count) { | 685 int* global_count) { |
| 683 // If it was not possible to allocate the variable at compile time, we | 686 // If it was not possible to allocate the variable at compile time, we |
| 684 // need to "declare" it at runtime to make sure it actually exists in the | 687 // need to "declare" it at runtime to make sure it actually exists in the |
| 685 // local context. | 688 // local context. |
| 686 Variable* variable = proxy->var(); | 689 Variable* variable = proxy->var(); |
| 690 bool binding_needs_init = |
| 691 mode == CONST || mode == CONST_HARMONY || mode == LET; |
| 687 switch (variable->location()) { | 692 switch (variable->location()) { |
| 688 case Variable::UNALLOCATED: | 693 case Variable::UNALLOCATED: |
| 689 ++(*global_count); | 694 ++(*global_count); |
| 690 break; | 695 break; |
| 691 | 696 |
| 692 case Variable::PARAMETER: | 697 case Variable::PARAMETER: |
| 693 case Variable::LOCAL: | 698 case Variable::LOCAL: |
| 694 if (function != NULL) { | 699 if (function != NULL) { |
| 695 Comment cmnt(masm_, "[ Declaration"); | 700 Comment cmnt(masm_, "[ Declaration"); |
| 696 VisitForAccumulatorValue(function); | 701 VisitForAccumulatorValue(function); |
| 697 __ movq(StackOperand(variable), result_register()); | 702 __ movq(StackOperand(variable), result_register()); |
| 698 } else if (mode == CONST || mode == LET) { | 703 } else if (binding_needs_init) { |
| 699 Comment cmnt(masm_, "[ Declaration"); | 704 Comment cmnt(masm_, "[ Declaration"); |
| 700 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 705 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 701 __ movq(StackOperand(variable), kScratchRegister); | 706 __ movq(StackOperand(variable), kScratchRegister); |
| 702 } | 707 } |
| 703 break; | 708 break; |
| 704 | 709 |
| 705 case Variable::CONTEXT: | 710 case Variable::CONTEXT: |
| 706 // The variable in the decl always resides in the current function | 711 // The variable in the decl always resides in the current function |
| 707 // context. | 712 // context. |
| 708 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 713 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 721 int offset = Context::SlotOffset(variable->index()); | 726 int offset = Context::SlotOffset(variable->index()); |
| 722 // We know that we have written a function, which is not a smi. | 727 // We know that we have written a function, which is not a smi. |
| 723 __ RecordWriteContextSlot(rsi, | 728 __ RecordWriteContextSlot(rsi, |
| 724 offset, | 729 offset, |
| 725 result_register(), | 730 result_register(), |
| 726 rcx, | 731 rcx, |
| 727 kDontSaveFPRegs, | 732 kDontSaveFPRegs, |
| 728 EMIT_REMEMBERED_SET, | 733 EMIT_REMEMBERED_SET, |
| 729 OMIT_SMI_CHECK); | 734 OMIT_SMI_CHECK); |
| 730 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 735 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 731 } else if (mode == CONST || mode == LET) { | 736 } else if (binding_needs_init) { |
| 732 Comment cmnt(masm_, "[ Declaration"); | 737 Comment cmnt(masm_, "[ Declaration"); |
| 733 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 738 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 734 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); | 739 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); |
| 735 // No write barrier since the hole value is in old space. | 740 // No write barrier since the hole value is in old space. |
| 736 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 741 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 737 } | 742 } |
| 738 break; | 743 break; |
| 739 | 744 |
| 740 case Variable::LOOKUP: { | 745 case Variable::LOOKUP: { |
| 741 Comment cmnt(masm_, "[ Declaration"); | 746 Comment cmnt(masm_, "[ Declaration"); |
| 742 __ push(rsi); | 747 __ push(rsi); |
| 743 __ Push(variable->name()); | 748 __ Push(variable->name()); |
| 744 // Declaration nodes are always introduced in one of three modes. | 749 // Declaration nodes are always introduced in one of four modes. |
| 745 ASSERT(mode == VAR || mode == CONST || mode == LET); | 750 ASSERT(mode == VAR || |
| 746 PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; | 751 mode == CONST || |
| 752 mode == CONST_HARMONY || |
| 753 mode == LET); |
| 754 PropertyAttributes attr = |
| 755 (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; |
| 747 __ Push(Smi::FromInt(attr)); | 756 __ Push(Smi::FromInt(attr)); |
| 748 // Push initial value, if any. | 757 // Push initial value, if any. |
| 749 // Note: For variables we must not push an initial value (such as | 758 // Note: For variables we must not push an initial value (such as |
| 750 // 'undefined') because we may have a (legal) redeclaration and we | 759 // 'undefined') because we may have a (legal) redeclaration and we |
| 751 // must not destroy the current value. | 760 // must not destroy the current value. |
| 752 if (function != NULL) { | 761 if (function != NULL) { |
| 753 VisitForStackValue(function); | 762 VisitForStackValue(function); |
| 754 } else if (mode == CONST || mode == LET) { | 763 } else if (binding_needs_init) { |
| 755 __ PushRoot(Heap::kTheHoleValueRootIndex); | 764 __ PushRoot(Heap::kTheHoleValueRootIndex); |
| 756 } else { | 765 } else { |
| 757 __ Push(Smi::FromInt(0)); // Indicates no initial value. | 766 __ Push(Smi::FromInt(0)); // Indicates no initial value. |
| 758 } | 767 } |
| 759 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 768 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 760 break; | 769 break; |
| 761 } | 770 } |
| 762 } | 771 } |
| 763 } | 772 } |
| 764 | 773 |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 883 Label convert, done_convert; | 892 Label convert, done_convert; |
| 884 __ JumpIfSmi(rax, &convert); | 893 __ JumpIfSmi(rax, &convert); |
| 885 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); | 894 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); |
| 886 __ j(above_equal, &done_convert); | 895 __ j(above_equal, &done_convert); |
| 887 __ bind(&convert); | 896 __ bind(&convert); |
| 888 __ push(rax); | 897 __ push(rax); |
| 889 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 898 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 890 __ bind(&done_convert); | 899 __ bind(&done_convert); |
| 891 __ push(rax); | 900 __ push(rax); |
| 892 | 901 |
| 902 // Check for proxies. |
| 903 Label call_runtime; |
| 904 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 905 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx); |
| 906 __ j(below_equal, &call_runtime); |
| 907 |
| 893 // Check cache validity in generated code. This is a fast case for | 908 // Check cache validity in generated code. This is a fast case for |
| 894 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | 909 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
| 895 // guarantee cache validity, call the runtime system to check cache | 910 // guarantee cache validity, call the runtime system to check cache |
| 896 // validity or get the property names in a fixed array. | 911 // validity or get the property names in a fixed array. |
| 897 Label next, call_runtime; | 912 Label next; |
| 898 Register empty_fixed_array_value = r8; | 913 Register empty_fixed_array_value = r8; |
| 899 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); | 914 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); |
| 900 Register empty_descriptor_array_value = r9; | 915 Register empty_descriptor_array_value = r9; |
| 901 __ LoadRoot(empty_descriptor_array_value, | 916 __ LoadRoot(empty_descriptor_array_value, |
| 902 Heap::kEmptyDescriptorArrayRootIndex); | 917 Heap::kEmptyDescriptorArrayRootIndex); |
| 903 __ movq(rcx, rax); | 918 __ movq(rcx, rax); |
| 904 __ bind(&next); | 919 __ bind(&next); |
| 905 | 920 |
| 906 // Check that there are no elements. Register rcx contains the | 921 // Check that there are no elements. Register rcx contains the |
| 907 // current JS object we've reached through the prototype chain. | 922 // current JS object we've reached through the prototype chain. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 963 | 978 |
| 964 // Setup the four remaining stack slots. | 979 // Setup the four remaining stack slots. |
| 965 __ push(rax); // Map. | 980 __ push(rax); // Map. |
| 966 __ push(rdx); // Enumeration cache. | 981 __ push(rdx); // Enumeration cache. |
| 967 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); | 982 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); |
| 968 __ push(rax); // Enumeration cache length (as smi). | 983 __ push(rax); // Enumeration cache length (as smi). |
| 969 __ Push(Smi::FromInt(0)); // Initial index. | 984 __ Push(Smi::FromInt(0)); // Initial index. |
| 970 __ jmp(&loop); | 985 __ jmp(&loop); |
| 971 | 986 |
| 972 // We got a fixed array in register rax. Iterate through that. | 987 // We got a fixed array in register rax. Iterate through that. |
| 988 Label non_proxy; |
| 973 __ bind(&fixed_array); | 989 __ bind(&fixed_array); |
| 974 __ Push(Smi::FromInt(0)); // Map (0) - force slow check. | 990 __ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check |
| 975 __ push(rax); | 991 __ movq(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object |
| 992 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 993 __ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx); |
| 994 __ j(above, &non_proxy); |
| 995 __ Move(rbx, Smi::FromInt(0)); // Zero indicates proxy |
| 996 __ bind(&non_proxy); |
| 997 __ push(rbx); // Smi |
| 998 __ push(rax); // Array |
| 976 __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset)); | 999 __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset)); |
| 977 __ push(rax); // Fixed array length (as smi). | 1000 __ push(rax); // Fixed array length (as smi). |
| 978 __ Push(Smi::FromInt(0)); // Initial index. | 1001 __ Push(Smi::FromInt(0)); // Initial index. |
| 979 | 1002 |
| 980 // Generate code for doing the condition check. | 1003 // Generate code for doing the condition check. |
| 981 __ bind(&loop); | 1004 __ bind(&loop); |
| 982 __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index. | 1005 __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index. |
| 983 __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length. | 1006 __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length. |
| 984 __ j(above_equal, loop_statement.break_label()); | 1007 __ j(above_equal, loop_statement.break_label()); |
| 985 | 1008 |
| 986 // Get the current entry of the array into register rbx. | 1009 // Get the current entry of the array into register rbx. |
| 987 __ movq(rbx, Operand(rsp, 2 * kPointerSize)); | 1010 __ movq(rbx, Operand(rsp, 2 * kPointerSize)); |
| 988 SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2); | 1011 SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2); |
| 989 __ movq(rbx, FieldOperand(rbx, | 1012 __ movq(rbx, FieldOperand(rbx, |
| 990 index.reg, | 1013 index.reg, |
| 991 index.scale, | 1014 index.scale, |
| 992 FixedArray::kHeaderSize)); | 1015 FixedArray::kHeaderSize)); |
| 993 | 1016 |
| 994 // Get the expected map from the stack or a zero map in the | 1017 // Get the expected map from the stack or a smi in the |
| 995 // permanent slow case into register rdx. | 1018 // permanent slow case into register rdx. |
| 996 __ movq(rdx, Operand(rsp, 3 * kPointerSize)); | 1019 __ movq(rdx, Operand(rsp, 3 * kPointerSize)); |
| 997 | 1020 |
| 998 // Check if the expected map still matches that of the enumerable. | 1021 // Check if the expected map still matches that of the enumerable. |
| 999 // If not, we have to filter the key. | 1022 // If not, we may have to filter the key. |
| 1000 Label update_each; | 1023 Label update_each; |
| 1001 __ movq(rcx, Operand(rsp, 4 * kPointerSize)); | 1024 __ movq(rcx, Operand(rsp, 4 * kPointerSize)); |
| 1002 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset)); | 1025 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset)); |
| 1003 __ j(equal, &update_each, Label::kNear); | 1026 __ j(equal, &update_each, Label::kNear); |
| 1004 | 1027 |
| 1028 // For proxies, no filtering is done. |
| 1029 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet. |
| 1030 __ Cmp(rdx, Smi::FromInt(0)); |
| 1031 __ j(equal, &update_each, Label::kNear); |
| 1032 |
| 1005 // Convert the entry to a string or null if it isn't a property | 1033 // Convert the entry to a string or null if it isn't a property |
| 1006 // anymore. If the property has been removed while iterating, we | 1034 // anymore. If the property has been removed while iterating, we |
| 1007 // just skip it. | 1035 // just skip it. |
| 1008 __ push(rcx); // Enumerable. | 1036 __ push(rcx); // Enumerable. |
| 1009 __ push(rbx); // Current entry. | 1037 __ push(rbx); // Current entry. |
| 1010 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); | 1038 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
| 1011 __ Cmp(rax, Smi::FromInt(0)); | 1039 __ Cmp(rax, Smi::FromInt(0)); |
| 1012 __ j(equal, loop_statement.continue_label()); | 1040 __ j(equal, loop_statement.continue_label()); |
| 1013 __ movq(rbx, rax); | 1041 __ movq(rbx, rax); |
| 1014 | 1042 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1048 // space for nested functions that don't need literals cloning. If | 1076 // space for nested functions that don't need literals cloning. If |
| 1049 // we're running with the --always-opt or the --prepare-always-opt | 1077 // we're running with the --always-opt or the --prepare-always-opt |
| 1050 // flag, we need to use the runtime function so that the new function | 1078 // flag, we need to use the runtime function so that the new function |
| 1051 // we are creating here gets a chance to have its code optimized and | 1079 // we are creating here gets a chance to have its code optimized and |
| 1052 // doesn't just get a copy of the existing unoptimized code. | 1080 // doesn't just get a copy of the existing unoptimized code. |
| 1053 if (!FLAG_always_opt && | 1081 if (!FLAG_always_opt && |
| 1054 !FLAG_prepare_always_opt && | 1082 !FLAG_prepare_always_opt && |
| 1055 !pretenure && | 1083 !pretenure && |
| 1056 scope()->is_function_scope() && | 1084 scope()->is_function_scope() && |
| 1057 info->num_literals() == 0) { | 1085 info->num_literals() == 0) { |
| 1058 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode); | 1086 FastNewClosureStub stub(info->strict_mode_flag()); |
| 1059 __ Push(info); | 1087 __ Push(info); |
| 1060 __ CallStub(&stub); | 1088 __ CallStub(&stub); |
| 1061 } else { | 1089 } else { |
| 1062 __ push(rsi); | 1090 __ push(rsi); |
| 1063 __ Push(info); | 1091 __ Push(info); |
| 1064 __ Push(pretenure | 1092 __ Push(pretenure |
| 1065 ? isolate()->factory()->true_value() | 1093 ? isolate()->factory()->true_value() |
| 1066 : isolate()->factory()->false_value()); | 1094 : isolate()->factory()->false_value()); |
| 1067 __ CallRuntime(Runtime::kNewClosure, 3); | 1095 __ CallRuntime(Runtime::kNewClosure, 3); |
| 1068 } | 1096 } |
| 1069 context()->Plug(rax); | 1097 context()->Plug(rax); |
| 1070 } | 1098 } |
| 1071 | 1099 |
| 1072 | 1100 |
| 1073 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 1101 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
| 1074 Comment cmnt(masm_, "[ VariableProxy"); | 1102 Comment cmnt(masm_, "[ VariableProxy"); |
| 1075 EmitVariableLoad(expr); | 1103 EmitVariableLoad(expr); |
| 1076 } | 1104 } |
| 1077 | 1105 |
| 1078 | 1106 |
| 1079 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, | 1107 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, |
| 1080 TypeofState typeof_state, | 1108 TypeofState typeof_state, |
| 1081 Label* slow) { | 1109 Label* slow) { |
| 1082 Register context = rsi; | 1110 Register context = rsi; |
| 1083 Register temp = rdx; | 1111 Register temp = rdx; |
| 1084 | 1112 |
| 1085 Scope* s = scope(); | 1113 Scope* s = scope(); |
| 1086 while (s != NULL) { | 1114 while (s != NULL) { |
| 1087 if (s->num_heap_slots() > 0) { | 1115 if (s->num_heap_slots() > 0) { |
| 1088 if (s->calls_eval()) { | 1116 if (s->calls_non_strict_eval()) { |
| 1089 // Check that extension is NULL. | 1117 // Check that extension is NULL. |
| 1090 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), | 1118 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), |
| 1091 Immediate(0)); | 1119 Immediate(0)); |
| 1092 __ j(not_equal, slow); | 1120 __ j(not_equal, slow); |
| 1093 } | 1121 } |
| 1094 // Load next context in chain. | 1122 // Load next context in chain. |
| 1095 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); | 1123 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); |
| 1096 // Walk the rest of the chain without clobbering rsi. | 1124 // Walk the rest of the chain without clobbering rsi. |
| 1097 context = temp; | 1125 context = temp; |
| 1098 } | 1126 } |
| 1099 // If no outer scope calls eval, we do not need to check more | 1127 // If no outer scope calls eval, we do not need to check more |
| 1100 // context extensions. If we have reached an eval scope, we check | 1128 // context extensions. If we have reached an eval scope, we check |
| 1101 // all extensions from this point. | 1129 // all extensions from this point. |
| 1102 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; | 1130 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break; |
| 1103 s = s->outer_scope(); | 1131 s = s->outer_scope(); |
| 1104 } | 1132 } |
| 1105 | 1133 |
| 1106 if (s != NULL && s->is_eval_scope()) { | 1134 if (s != NULL && s->is_eval_scope()) { |
| 1107 // Loop up the context chain. There is no frame effect so it is | 1135 // Loop up the context chain. There is no frame effect so it is |
| 1108 // safe to use raw labels here. | 1136 // safe to use raw labels here. |
| 1109 Label next, fast; | 1137 Label next, fast; |
| 1110 if (!context.is(temp)) { | 1138 if (!context.is(temp)) { |
| 1111 __ movq(temp, context); | 1139 __ movq(temp, context); |
| 1112 } | 1140 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1138 | 1166 |
| 1139 | 1167 |
| 1140 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, | 1168 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, |
| 1141 Label* slow) { | 1169 Label* slow) { |
| 1142 ASSERT(var->IsContextSlot()); | 1170 ASSERT(var->IsContextSlot()); |
| 1143 Register context = rsi; | 1171 Register context = rsi; |
| 1144 Register temp = rbx; | 1172 Register temp = rbx; |
| 1145 | 1173 |
| 1146 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { | 1174 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { |
| 1147 if (s->num_heap_slots() > 0) { | 1175 if (s->num_heap_slots() > 0) { |
| 1148 if (s->calls_eval()) { | 1176 if (s->calls_non_strict_eval()) { |
| 1149 // Check that extension is NULL. | 1177 // Check that extension is NULL. |
| 1150 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), | 1178 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), |
| 1151 Immediate(0)); | 1179 Immediate(0)); |
| 1152 __ j(not_equal, slow); | 1180 __ j(not_equal, slow); |
| 1153 } | 1181 } |
| 1154 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); | 1182 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); |
| 1155 // Walk the rest of the chain without clobbering rsi. | 1183 // Walk the rest of the chain without clobbering rsi. |
| 1156 context = temp; | 1184 context = temp; |
| 1157 } | 1185 } |
| 1158 } | 1186 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1175 // eval-introduced variables. Eval is used a lot without | 1203 // eval-introduced variables. Eval is used a lot without |
| 1176 // introducing variables. In those cases, we do not want to | 1204 // introducing variables. In those cases, we do not want to |
| 1177 // perform a runtime call for all variables in the scope | 1205 // perform a runtime call for all variables in the scope |
| 1178 // containing the eval. | 1206 // containing the eval. |
| 1179 if (var->mode() == DYNAMIC_GLOBAL) { | 1207 if (var->mode() == DYNAMIC_GLOBAL) { |
| 1180 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1208 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
| 1181 __ jmp(done); | 1209 __ jmp(done); |
| 1182 } else if (var->mode() == DYNAMIC_LOCAL) { | 1210 } else if (var->mode() == DYNAMIC_LOCAL) { |
| 1183 Variable* local = var->local_if_not_shadowed(); | 1211 Variable* local = var->local_if_not_shadowed(); |
| 1184 __ movq(rax, ContextSlotOperandCheckExtensions(local, slow)); | 1212 __ movq(rax, ContextSlotOperandCheckExtensions(local, slow)); |
| 1185 if (local->mode() == CONST || local->mode() == LET) { | 1213 if (local->mode() == CONST || |
| 1214 local->mode() == CONST_HARMONY || |
| 1215 local->mode() == LET) { |
| 1186 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1216 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 1187 __ j(not_equal, done); | 1217 __ j(not_equal, done); |
| 1188 if (local->mode() == CONST) { | 1218 if (local->mode() == CONST) { |
| 1189 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1219 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 1190 } else { // LET | 1220 } else { // LET || CONST_HARMONY |
| 1191 __ Push(var->name()); | 1221 __ Push(var->name()); |
| 1192 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1222 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1193 } | 1223 } |
| 1194 } | 1224 } |
| 1195 __ jmp(done); | 1225 __ jmp(done); |
| 1196 } | 1226 } |
| 1197 } | 1227 } |
| 1198 | 1228 |
| 1199 | 1229 |
| 1200 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1230 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1214 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1244 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1215 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1245 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1216 context()->Plug(rax); | 1246 context()->Plug(rax); |
| 1217 break; | 1247 break; |
| 1218 } | 1248 } |
| 1219 | 1249 |
| 1220 case Variable::PARAMETER: | 1250 case Variable::PARAMETER: |
| 1221 case Variable::LOCAL: | 1251 case Variable::LOCAL: |
| 1222 case Variable::CONTEXT: { | 1252 case Variable::CONTEXT: { |
| 1223 Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot"); | 1253 Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot"); |
| 1224 if (var->mode() != LET && var->mode() != CONST) { | 1254 if (!var->binding_needs_init()) { |
| 1225 context()->Plug(var); | 1255 context()->Plug(var); |
| 1226 } else { | 1256 } else { |
| 1227 // Let and const need a read barrier. | 1257 // Let and const need a read barrier. |
| 1228 Label done; | 1258 Label done; |
| 1229 GetVar(rax, var); | 1259 GetVar(rax, var); |
| 1230 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1260 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 1231 __ j(not_equal, &done, Label::kNear); | 1261 __ j(not_equal, &done, Label::kNear); |
| 1232 if (var->mode() == LET) { | 1262 if (var->mode() == LET || var->mode() == CONST_HARMONY) { |
| 1263 // Throw a reference error when using an uninitialized let/const |
| 1264 // binding in harmony mode. |
| 1233 __ Push(var->name()); | 1265 __ Push(var->name()); |
| 1234 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1266 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1235 } else { // CONST | 1267 } else { |
| 1268 // Uninitalized const bindings outside of harmony mode are unholed. |
| 1269 ASSERT(var->mode() == CONST); |
| 1236 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1270 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 1237 } | 1271 } |
| 1238 __ bind(&done); | 1272 __ bind(&done); |
| 1239 context()->Plug(rax); | 1273 context()->Plug(rax); |
| 1240 } | 1274 } |
| 1241 break; | 1275 break; |
| 1242 } | 1276 } |
| 1243 | 1277 |
| 1244 case Variable::LOOKUP: { | 1278 case Variable::LOOKUP: { |
| 1245 Label done, slow; | 1279 Label done, slow; |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1410 context()->Plug(rax); | 1444 context()->Plug(rax); |
| 1411 } | 1445 } |
| 1412 } | 1446 } |
| 1413 | 1447 |
| 1414 | 1448 |
| 1415 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 1449 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 1416 Comment cmnt(masm_, "[ ArrayLiteral"); | 1450 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 1417 | 1451 |
| 1418 ZoneList<Expression*>* subexprs = expr->values(); | 1452 ZoneList<Expression*>* subexprs = expr->values(); |
| 1419 int length = subexprs->length(); | 1453 int length = subexprs->length(); |
| 1454 Handle<FixedArray> constant_elements = expr->constant_elements(); |
| 1455 ASSERT_EQ(2, constant_elements->length()); |
| 1456 ElementsKind constant_elements_kind = |
| 1457 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); |
| 1458 Handle<FixedArrayBase> constant_elements_values( |
| 1459 FixedArrayBase::cast(constant_elements->get(1))); |
| 1420 | 1460 |
| 1421 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 1461 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1422 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); | 1462 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); |
| 1423 __ Push(Smi::FromInt(expr->literal_index())); | 1463 __ Push(Smi::FromInt(expr->literal_index())); |
| 1424 __ Push(expr->constant_elements()); | 1464 __ Push(constant_elements); |
| 1425 if (expr->constant_elements()->map() == | 1465 if (constant_elements_values->map() == |
| 1426 isolate()->heap()->fixed_cow_array_map()) { | 1466 isolate()->heap()->fixed_cow_array_map()) { |
| 1427 FastCloneShallowArrayStub stub( | 1467 FastCloneShallowArrayStub stub( |
| 1428 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); | 1468 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); |
| 1429 __ CallStub(&stub); | 1469 __ CallStub(&stub); |
| 1430 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1); | 1470 __ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1); |
| 1431 } else if (expr->depth() > 1) { | 1471 } else if (expr->depth() > 1) { |
| 1432 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); | 1472 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); |
| 1433 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { | 1473 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { |
| 1434 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 1474 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); |
| 1435 } else { | 1475 } else { |
| 1436 FastCloneShallowArrayStub stub( | 1476 ASSERT(constant_elements_kind == FAST_ELEMENTS || |
| 1437 FastCloneShallowArrayStub::CLONE_ELEMENTS, length); | 1477 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS || |
| 1478 FLAG_smi_only_arrays); |
| 1479 FastCloneShallowArrayStub::Mode mode = |
| 1480 constant_elements_kind == FAST_DOUBLE_ELEMENTS |
| 1481 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS |
| 1482 : FastCloneShallowArrayStub::CLONE_ELEMENTS; |
| 1483 FastCloneShallowArrayStub stub(mode, length); |
| 1438 __ CallStub(&stub); | 1484 __ CallStub(&stub); |
| 1439 } | 1485 } |
| 1440 | 1486 |
| 1441 bool result_saved = false; // Is the result saved to the stack? | 1487 bool result_saved = false; // Is the result saved to the stack? |
| 1442 | 1488 |
| 1443 // Emit code to evaluate all the non-constant subexpressions and to store | 1489 // Emit code to evaluate all the non-constant subexpressions and to store |
| 1444 // them into the newly cloned array. | 1490 // them into the newly cloned array. |
| 1445 for (int i = 0; i < length; i++) { | 1491 for (int i = 0; i < length; i++) { |
| 1446 Expression* subexpr = subexprs->at(i); | 1492 Expression* subexpr = subexprs->at(i); |
| 1447 // If the subexpression is a literal or a simple materialized literal it | 1493 // If the subexpression is a literal or a simple materialized literal it |
| 1448 // is already set in the cloned array. | 1494 // is already set in the cloned array. |
| 1449 if (subexpr->AsLiteral() != NULL || | 1495 if (subexpr->AsLiteral() != NULL || |
| 1450 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 1496 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 1451 continue; | 1497 continue; |
| 1452 } | 1498 } |
| 1453 | 1499 |
| 1454 if (!result_saved) { | 1500 if (!result_saved) { |
| 1455 __ push(rax); | 1501 __ push(rax); |
| 1456 result_saved = true; | 1502 result_saved = true; |
| 1457 } | 1503 } |
| 1458 VisitForAccumulatorValue(subexpr); | 1504 VisitForAccumulatorValue(subexpr); |
| 1459 | 1505 |
| 1460 // Store the subexpression value in the array's elements. | 1506 // Store the subexpression value in the array's elements. |
| 1461 __ movq(r8, Operand(rsp, 0)); // Copy of array literal. | 1507 __ movq(r8, Operand(rsp, 0)); // Copy of array literal. |
| 1508 __ movq(rdi, FieldOperand(r8, JSObject::kMapOffset)); |
| 1462 __ movq(rbx, FieldOperand(r8, JSObject::kElementsOffset)); | 1509 __ movq(rbx, FieldOperand(r8, JSObject::kElementsOffset)); |
| 1463 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1510 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 1511 |
| 1512 Label element_done; |
| 1513 Label double_elements; |
| 1514 Label smi_element; |
| 1515 Label slow_elements; |
| 1516 Label fast_elements; |
| 1517 __ CheckFastElements(rdi, &double_elements); |
| 1518 |
| 1519 // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS |
| 1520 __ JumpIfSmi(result_register(), &smi_element); |
| 1521 __ CheckFastSmiOnlyElements(rdi, &fast_elements); |
| 1522 |
| 1523 // Store into the array literal requires a elements transition. Call into |
| 1524 // the runtime. |
| 1525 __ bind(&slow_elements); |
| 1526 __ push(r8); // Copy of array literal. |
| 1527 __ Push(Smi::FromInt(i)); |
| 1528 __ push(result_register()); |
| 1529 __ Push(Smi::FromInt(NONE)); // PropertyAttributes |
| 1530 __ Push(Smi::FromInt(strict_mode_flag())); // Strict mode. |
| 1531 __ CallRuntime(Runtime::kSetProperty, 5); |
| 1532 __ jmp(&element_done); |
| 1533 |
| 1534 // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. |
| 1535 __ bind(&double_elements); |
| 1536 __ movq(rcx, Immediate(i)); |
| 1537 __ StoreNumberToDoubleElements(result_register(), |
| 1538 rbx, |
| 1539 rcx, |
| 1540 xmm0, |
| 1541 &slow_elements); |
| 1542 __ jmp(&element_done); |
| 1543 |
| 1544 // Array literal has ElementsKind of FAST_ELEMENTS and value is an object. |
| 1545 __ bind(&fast_elements); |
| 1464 __ movq(FieldOperand(rbx, offset), result_register()); | 1546 __ movq(FieldOperand(rbx, offset), result_register()); |
| 1465 | |
| 1466 Label no_map_change; | |
| 1467 __ JumpIfSmi(result_register(), &no_map_change); | |
| 1468 // Update the write barrier for the array store. | 1547 // Update the write barrier for the array store. |
| 1469 __ RecordWriteField(rbx, offset, result_register(), rcx, | 1548 __ RecordWriteField(rbx, offset, result_register(), rcx, |
| 1470 kDontSaveFPRegs, | 1549 kDontSaveFPRegs, |
| 1471 EMIT_REMEMBERED_SET, | 1550 EMIT_REMEMBERED_SET, |
| 1472 OMIT_SMI_CHECK); | 1551 OMIT_SMI_CHECK); |
| 1473 __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset)); | 1552 __ jmp(&element_done); |
| 1474 __ CheckFastSmiOnlyElements(rdi, &no_map_change, Label::kNear); | 1553 |
| 1475 __ push(r8); | 1554 // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or |
| 1476 __ CallRuntime(Runtime::kNonSmiElementStored, 1); | 1555 // FAST_ELEMENTS, and value is Smi. |
| 1477 __ bind(&no_map_change); | 1556 __ bind(&smi_element); |
| 1557 __ movq(FieldOperand(rbx, offset), result_register()); |
| 1558 // Fall through |
| 1559 |
| 1560 __ bind(&element_done); |
| 1478 | 1561 |
| 1479 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1562 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
| 1480 } | 1563 } |
| 1481 | 1564 |
| 1482 if (result_saved) { | 1565 if (result_saved) { |
| 1483 context()->PlugTOS(); | 1566 context()->PlugTOS(); |
| 1484 } else { | 1567 } else { |
| 1485 context()->Plug(rax); | 1568 context()->Plug(rax); |
| 1486 } | 1569 } |
| 1487 } | 1570 } |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1798 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1881 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1799 __ bind(&assign); | 1882 __ bind(&assign); |
| 1800 __ movq(location, rax); | 1883 __ movq(location, rax); |
| 1801 if (var->IsContextSlot()) { | 1884 if (var->IsContextSlot()) { |
| 1802 __ movq(rdx, rax); | 1885 __ movq(rdx, rax); |
| 1803 __ RecordWriteContextSlot( | 1886 __ RecordWriteContextSlot( |
| 1804 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); | 1887 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
| 1805 } | 1888 } |
| 1806 } | 1889 } |
| 1807 | 1890 |
| 1808 } else if (var->mode() != CONST) { | 1891 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
| 1809 // Assignment to var or initializing assignment to let. | 1892 // Assignment to var or initializing assignment to let/const |
| 1893 // in harmony mode. |
| 1810 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1894 if (var->IsStackAllocated() || var->IsContextSlot()) { |
| 1811 MemOperand location = VarOperand(var, rcx); | 1895 MemOperand location = VarOperand(var, rcx); |
| 1812 if (FLAG_debug_code && op == Token::INIT_LET) { | 1896 if (FLAG_debug_code && op == Token::INIT_LET) { |
| 1813 // Check for an uninitialized let binding. | 1897 // Check for an uninitialized let binding. |
| 1814 __ movq(rdx, location); | 1898 __ movq(rdx, location); |
| 1815 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1899 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1816 __ Check(equal, "Let binding re-initialization."); | 1900 __ Check(equal, "Let binding re-initialization."); |
| 1817 } | 1901 } |
| 1818 // Perform the assignment. | 1902 // Perform the assignment. |
| 1819 __ movq(location, rax); | 1903 __ movq(location, rax); |
| (...skipping 830 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2650 // Allocate a heap number. | 2734 // Allocate a heap number. |
| 2651 __ CallRuntime(Runtime::kNumberAlloc, 0); | 2735 __ CallRuntime(Runtime::kNumberAlloc, 0); |
| 2652 __ movq(rbx, rax); | 2736 __ movq(rbx, rax); |
| 2653 | 2737 |
| 2654 __ bind(&heapnumber_allocated); | 2738 __ bind(&heapnumber_allocated); |
| 2655 | 2739 |
| 2656 // Return a random uint32 number in rax. | 2740 // Return a random uint32 number in rax. |
| 2657 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs. | 2741 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs. |
| 2658 __ PrepareCallCFunction(1); | 2742 __ PrepareCallCFunction(1); |
| 2659 #ifdef _WIN64 | 2743 #ifdef _WIN64 |
| 2660 __ LoadAddress(rcx, ExternalReference::isolate_address()); | 2744 __ movq(rcx, ContextOperand(context_register(), Context::GLOBAL_INDEX)); |
| 2745 __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalContextOffset)); |
| 2746 |
| 2661 #else | 2747 #else |
| 2662 __ LoadAddress(rdi, ExternalReference::isolate_address()); | 2748 __ movq(rdi, ContextOperand(context_register(), Context::GLOBAL_INDEX)); |
| 2749 __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset)); |
| 2663 #endif | 2750 #endif |
| 2664 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); | 2751 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); |
| 2665 | 2752 |
| 2666 // Convert 32 random bits in rax to 0.(32 random bits) in a double | 2753 // Convert 32 random bits in rax to 0.(32 random bits) in a double |
| 2667 // by computing: | 2754 // by computing: |
| 2668 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). | 2755 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
| 2669 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single. | 2756 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
| 2670 __ movd(xmm1, rcx); | 2757 __ movd(xmm1, rcx); |
| 2671 __ movd(xmm0, rax); | 2758 __ movd(xmm0, rax); |
| 2672 __ cvtss2sd(xmm1, xmm1); | 2759 __ cvtss2sd(xmm1, xmm1); |
| (...skipping 1317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3990 break; | 4077 break; |
| 3991 } | 4078 } |
| 3992 | 4079 |
| 3993 default: { | 4080 default: { |
| 3994 VisitForAccumulatorValue(expr->right()); | 4081 VisitForAccumulatorValue(expr->right()); |
| 3995 Condition cc = no_condition; | 4082 Condition cc = no_condition; |
| 3996 switch (op) { | 4083 switch (op) { |
| 3997 case Token::EQ_STRICT: | 4084 case Token::EQ_STRICT: |
| 3998 case Token::EQ: | 4085 case Token::EQ: |
| 3999 cc = equal; | 4086 cc = equal; |
| 4000 __ pop(rdx); | |
| 4001 break; | 4087 break; |
| 4002 case Token::LT: | 4088 case Token::LT: |
| 4003 cc = less; | 4089 cc = less; |
| 4004 __ pop(rdx); | |
| 4005 break; | 4090 break; |
| 4006 case Token::GT: | 4091 case Token::GT: |
| 4007 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 4092 cc = greater; |
| 4008 cc = less; | |
| 4009 __ movq(rdx, result_register()); | |
| 4010 __ pop(rax); | |
| 4011 break; | 4093 break; |
| 4012 case Token::LTE: | 4094 case Token::LTE: |
| 4013 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 4095 cc = less_equal; |
| 4014 cc = greater_equal; | |
| 4015 __ movq(rdx, result_register()); | |
| 4016 __ pop(rax); | |
| 4017 break; | 4096 break; |
| 4018 case Token::GTE: | 4097 case Token::GTE: |
| 4019 cc = greater_equal; | 4098 cc = greater_equal; |
| 4020 __ pop(rdx); | |
| 4021 break; | 4099 break; |
| 4022 case Token::IN: | 4100 case Token::IN: |
| 4023 case Token::INSTANCEOF: | 4101 case Token::INSTANCEOF: |
| 4024 default: | 4102 default: |
| 4025 UNREACHABLE(); | 4103 UNREACHABLE(); |
| 4026 } | 4104 } |
| 4105 __ pop(rdx); |
| 4027 | 4106 |
| 4028 bool inline_smi_code = ShouldInlineSmiCase(op); | 4107 bool inline_smi_code = ShouldInlineSmiCase(op); |
| 4029 JumpPatchSite patch_site(masm_); | 4108 JumpPatchSite patch_site(masm_); |
| 4030 if (inline_smi_code) { | 4109 if (inline_smi_code) { |
| 4031 Label slow_case; | 4110 Label slow_case; |
| 4032 __ movq(rcx, rdx); | 4111 __ movq(rcx, rdx); |
| 4033 __ or_(rcx, rax); | 4112 __ or_(rcx, rax); |
| 4034 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear); | 4113 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear); |
| 4035 __ cmpq(rdx, rax); | 4114 __ cmpq(rdx, rax); |
| 4036 Split(cc, if_true, if_false, NULL); | 4115 Split(cc, if_true, if_false, NULL); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4195 *context_length = 0; | 4274 *context_length = 0; |
| 4196 return previous_; | 4275 return previous_; |
| 4197 } | 4276 } |
| 4198 | 4277 |
| 4199 | 4278 |
| 4200 #undef __ | 4279 #undef __ |
| 4201 | 4280 |
| 4202 } } // namespace v8::internal | 4281 } } // namespace v8::internal |
| 4203 | 4282 |
| 4204 #endif // V8_TARGET_ARCH_X64 | 4283 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |