OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 907 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
918 | 918 |
919 // Get the object to enumerate over. Both SpiderMonkey and JSC | 919 // Get the object to enumerate over. Both SpiderMonkey and JSC |
920 // ignore null and undefined in contrast to the specification; see | 920 // ignore null and undefined in contrast to the specification; see |
921 // ECMA-262 section 12.6.4. | 921 // ECMA-262 section 12.6.4. |
922 VisitForAccumulatorValue(stmt->enumerable()); | 922 VisitForAccumulatorValue(stmt->enumerable()); |
923 __ cmp(eax, isolate()->factory()->undefined_value()); | 923 __ cmp(eax, isolate()->factory()->undefined_value()); |
924 __ j(equal, &exit); | 924 __ j(equal, &exit); |
925 __ cmp(eax, isolate()->factory()->null_value()); | 925 __ cmp(eax, isolate()->factory()->null_value()); |
926 __ j(equal, &exit); | 926 __ j(equal, &exit); |
927 | 927 |
| 928 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG); |
| 929 |
928 // Convert the object to a JS object. | 930 // Convert the object to a JS object. |
929 Label convert, done_convert; | 931 Label convert, done_convert; |
930 __ JumpIfSmi(eax, &convert, Label::kNear); | 932 __ JumpIfSmi(eax, &convert, Label::kNear); |
931 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); | 933 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); |
932 __ j(above_equal, &done_convert, Label::kNear); | 934 __ j(above_equal, &done_convert, Label::kNear); |
933 __ bind(&convert); | 935 __ bind(&convert); |
934 __ push(eax); | 936 __ push(eax); |
935 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 937 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
936 __ bind(&done_convert); | 938 __ bind(&done_convert); |
937 __ push(eax); | 939 __ push(eax); |
938 | 940 |
939 // Check for proxies. | 941 // Check for proxies. |
940 Label call_runtime; | 942 Label call_runtime, use_cache, fixed_array; |
941 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 943 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
942 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx); | 944 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx); |
943 __ j(below_equal, &call_runtime); | 945 __ j(below_equal, &call_runtime); |
944 | 946 |
945 // Check cache validity in generated code. This is a fast case for | 947 // Check cache validity in generated code. This is a fast case for |
946 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | 948 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
947 // guarantee cache validity, call the runtime system to check cache | 949 // guarantee cache validity, call the runtime system to check cache |
948 // validity or get the property names in a fixed array. | 950 // validity or get the property names in a fixed array. |
949 Label next; | 951 __ CheckEnumCache(&call_runtime); |
950 __ mov(ecx, eax); | |
951 __ bind(&next); | |
952 | 952 |
953 // Check that there are no elements. Register ecx contains the | |
954 // current JS object we've reached through the prototype chain. | |
955 __ cmp(FieldOperand(ecx, JSObject::kElementsOffset), | |
956 isolate()->factory()->empty_fixed_array()); | |
957 __ j(not_equal, &call_runtime); | |
958 | |
959 // Check that instance descriptors are not empty so that we can | |
960 // check for an enum cache. Leave the map in ebx for the subsequent | |
961 // prototype load. | |
962 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); | |
963 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset)); | |
964 __ JumpIfSmi(edx, &call_runtime); | |
965 | |
966 // Check that there is an enum cache in the non-empty instance | |
967 // descriptors (edx). This is the case if the next enumeration | |
968 // index field does not contain a smi. | |
969 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | |
970 __ JumpIfSmi(edx, &call_runtime); | |
971 | |
972 // For all objects but the receiver, check that the cache is empty. | |
973 Label check_prototype; | |
974 __ cmp(ecx, eax); | |
975 __ j(equal, &check_prototype, Label::kNear); | |
976 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | |
977 __ cmp(edx, isolate()->factory()->empty_fixed_array()); | |
978 __ j(not_equal, &call_runtime); | |
979 | |
980 // Load the prototype from the map and loop if non-null. | |
981 __ bind(&check_prototype); | |
982 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); | |
983 __ cmp(ecx, isolate()->factory()->null_value()); | |
984 __ j(not_equal, &next); | |
985 | |
986 // The enum cache is valid. Load the map of the object being | |
987 // iterated over and use the cache for the iteration. | |
988 Label use_cache; | |
989 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 953 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
990 __ jmp(&use_cache, Label::kNear); | 954 __ jmp(&use_cache, Label::kNear); |
991 | 955 |
992 // Get the set of properties to enumerate. | 956 // Get the set of properties to enumerate. |
993 __ bind(&call_runtime); | 957 __ bind(&call_runtime); |
994 __ push(eax); // Duplicate the enumerable object on the stack. | 958 __ push(eax); |
995 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 959 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
996 | |
997 // If we got a map from the runtime call, we can do a fast | |
998 // modification check. Otherwise, we got a fixed array, and we have | |
999 // to do a slow check. | |
1000 Label fixed_array; | |
1001 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 960 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
1002 isolate()->factory()->meta_map()); | 961 isolate()->factory()->meta_map()); |
1003 __ j(not_equal, &fixed_array, Label::kNear); | 962 __ j(not_equal, &fixed_array); |
| 963 |
1004 | 964 |
1005 // We got a map in register eax. Get the enumeration cache from it. | 965 // We got a map in register eax. Get the enumeration cache from it. |
1006 __ bind(&use_cache); | 966 __ bind(&use_cache); |
1007 __ LoadInstanceDescriptors(eax, ecx); | 967 __ LoadInstanceDescriptors(eax, ecx); |
1008 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); | 968 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
1009 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 969 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
1010 | 970 |
1011 // Set up the four remaining stack slots. | 971 // Set up the four remaining stack slots. |
1012 __ push(eax); // Map. | 972 __ push(eax); // Map. |
1013 __ push(edx); // Enumeration cache. | 973 __ push(edx); // Enumeration cache. |
(...skipping 12 matching lines...) Expand all Loading... |
1026 __ j(above, &non_proxy); | 986 __ j(above, &non_proxy); |
1027 __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy | 987 __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy |
1028 __ bind(&non_proxy); | 988 __ bind(&non_proxy); |
1029 __ push(ebx); // Smi | 989 __ push(ebx); // Smi |
1030 __ push(eax); // Array | 990 __ push(eax); // Array |
1031 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 991 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
1032 __ push(eax); // Fixed array length (as smi). | 992 __ push(eax); // Fixed array length (as smi). |
1033 __ push(Immediate(Smi::FromInt(0))); // Initial index. | 993 __ push(Immediate(Smi::FromInt(0))); // Initial index. |
1034 | 994 |
1035 // Generate code for doing the condition check. | 995 // Generate code for doing the condition check. |
| 996 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); |
1036 __ bind(&loop); | 997 __ bind(&loop); |
1037 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. | 998 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. |
1038 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. | 999 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. |
1039 __ j(above_equal, loop_statement.break_label()); | 1000 __ j(above_equal, loop_statement.break_label()); |
1040 | 1001 |
1041 // Get the current entry of the array into register ebx. | 1002 // Get the current entry of the array into register ebx. |
1042 __ mov(ebx, Operand(esp, 2 * kPointerSize)); | 1003 __ mov(ebx, Operand(esp, 2 * kPointerSize)); |
1043 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); | 1004 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); |
1044 | 1005 |
1045 // Get the expected map from the stack or a smi in the | 1006 // Get the expected map from the stack or a smi in the |
(...skipping 22 matching lines...) Expand all Loading... |
1068 __ test(eax, eax); | 1029 __ test(eax, eax); |
1069 __ j(equal, loop_statement.continue_label()); | 1030 __ j(equal, loop_statement.continue_label()); |
1070 __ mov(ebx, eax); | 1031 __ mov(ebx, eax); |
1071 | 1032 |
1072 // Update the 'each' property or variable from the possibly filtered | 1033 // Update the 'each' property or variable from the possibly filtered |
1073 // entry in register ebx. | 1034 // entry in register ebx. |
1074 __ bind(&update_each); | 1035 __ bind(&update_each); |
1075 __ mov(result_register(), ebx); | 1036 __ mov(result_register(), ebx); |
1076 // Perform the assignment as if via '='. | 1037 // Perform the assignment as if via '='. |
1077 { EffectContext context(this); | 1038 { EffectContext context(this); |
1078 EmitAssignment(stmt->each(), stmt->AssignmentId()); | 1039 EmitAssignment(stmt->each()); |
1079 } | 1040 } |
1080 | 1041 |
1081 // Generate code for the body of the loop. | 1042 // Generate code for the body of the loop. |
1082 Visit(stmt->body()); | 1043 Visit(stmt->body()); |
1083 | 1044 |
1084 // Generate code for going to the next element by incrementing the | 1045 // Generate code for going to the next element by incrementing the |
1085 // index (smi) stored on top of the stack. | 1046 // index (smi) stored on top of the stack. |
1086 __ bind(loop_statement.continue_label()); | 1047 __ bind(loop_statement.continue_label()); |
1087 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); | 1048 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); |
1088 | 1049 |
1089 EmitStackCheck(stmt, &loop); | 1050 EmitStackCheck(stmt, &loop); |
1090 __ jmp(&loop); | 1051 __ jmp(&loop); |
1091 | 1052 |
1092 // Remove the pointers stored on the stack. | 1053 // Remove the pointers stored on the stack. |
1093 __ bind(loop_statement.break_label()); | 1054 __ bind(loop_statement.break_label()); |
1094 __ add(esp, Immediate(5 * kPointerSize)); | 1055 __ add(esp, Immediate(5 * kPointerSize)); |
1095 | 1056 |
1096 // Exit and decrement the loop depth. | 1057 // Exit and decrement the loop depth. |
| 1058 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
1097 __ bind(&exit); | 1059 __ bind(&exit); |
1098 decrement_loop_depth(); | 1060 decrement_loop_depth(); |
1099 } | 1061 } |
1100 | 1062 |
1101 | 1063 |
1102 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, | 1064 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, |
1103 bool pretenure) { | 1065 bool pretenure) { |
1104 // Use the fast case closure allocation code that allocates in new | 1066 // Use the fast case closure allocation code that allocates in new |
1105 // space for nested functions that don't need literals cloning. If | 1067 // space for nested functions that don't need literals cloning. If |
1106 // we're running with the --always-opt or the --prepare-always-opt | 1068 // we're running with the --always-opt or the --prepare-always-opt |
(...skipping 739 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1846 OverwriteMode mode) { | 1808 OverwriteMode mode) { |
1847 __ pop(edx); | 1809 __ pop(edx); |
1848 BinaryOpStub stub(op, mode); | 1810 BinaryOpStub stub(op, mode); |
1849 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. | 1811 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
1850 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); | 1812 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
1851 patch_site.EmitPatchInfo(); | 1813 patch_site.EmitPatchInfo(); |
1852 context()->Plug(eax); | 1814 context()->Plug(eax); |
1853 } | 1815 } |
1854 | 1816 |
1855 | 1817 |
1856 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1818 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
1857 // Invalid left-hand sides are rewritten to have a 'throw | 1819 // Invalid left-hand sides are rewritten to have a 'throw |
1858 // ReferenceError' on the left-hand side. | 1820 // ReferenceError' on the left-hand side. |
1859 if (!expr->IsValidLeftHandSide()) { | 1821 if (!expr->IsValidLeftHandSide()) { |
1860 VisitForEffect(expr); | 1822 VisitForEffect(expr); |
1861 return; | 1823 return; |
1862 } | 1824 } |
1863 | 1825 |
1864 // Left-hand side can only be a property, a global or a (parameter or local) | 1826 // Left-hand side can only be a property, a global or a (parameter or local) |
1865 // slot. | 1827 // slot. |
1866 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1828 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1898 __ mov(ecx, eax); | 1860 __ mov(ecx, eax); |
1899 __ pop(edx); | 1861 __ pop(edx); |
1900 __ pop(eax); // Restore value. | 1862 __ pop(eax); // Restore value. |
1901 Handle<Code> ic = is_classic_mode() | 1863 Handle<Code> ic = is_classic_mode() |
1902 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 1864 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
1903 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 1865 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
1904 __ call(ic); | 1866 __ call(ic); |
1905 break; | 1867 break; |
1906 } | 1868 } |
1907 } | 1869 } |
1908 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | |
1909 context()->Plug(eax); | 1870 context()->Plug(eax); |
1910 } | 1871 } |
1911 | 1872 |
1912 | 1873 |
1913 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1874 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
1914 Token::Value op) { | 1875 Token::Value op) { |
1915 if (var->IsUnallocated()) { | 1876 if (var->IsUnallocated()) { |
1916 // Global var, const, or let. | 1877 // Global var, const, or let. |
1917 __ mov(ecx, var->name()); | 1878 __ mov(ecx, var->name()); |
1918 __ mov(edx, GlobalObjectOperand()); | 1879 __ mov(edx, GlobalObjectOperand()); |
(...skipping 2507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4426 *context_length = 0; | 4387 *context_length = 0; |
4427 return previous_; | 4388 return previous_; |
4428 } | 4389 } |
4429 | 4390 |
4430 | 4391 |
4431 #undef __ | 4392 #undef __ |
4432 | 4393 |
4433 } } // namespace v8::internal | 4394 } } // namespace v8::internal |
4434 | 4395 |
4435 #endif // V8_TARGET_ARCH_IA32 | 4396 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |