| 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 __ CheckEnumCache(&call_runtime); |
| 946 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | |
| 947 // guarantee cache validity, call the runtime system to check cache | |
| 948 // validity or get the property names in a fixed array. | |
| 949 Label next; | |
| 950 __ mov(ecx, eax); | |
| 951 __ bind(&next); | |
| 952 | 948 |
| 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)); | 949 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 990 __ jmp(&use_cache, Label::kNear); | 950 __ jmp(&use_cache, Label::kNear); |
| 991 | 951 |
| 992 // Get the set of properties to enumerate. | 952 // Get the set of properties to enumerate. |
| 993 __ bind(&call_runtime); | 953 __ bind(&call_runtime); |
| 994 __ push(eax); // Duplicate the enumerable object on the stack. | 954 __ push(eax); |
| 995 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 955 __ 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), | 956 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 1002 isolate()->factory()->meta_map()); | 957 isolate()->factory()->meta_map()); |
| 1003 __ j(not_equal, &fixed_array, Label::kNear); | 958 __ j(not_equal, &fixed_array); |
| 959 |
| 1004 | 960 |
| 1005 // We got a map in register eax. Get the enumeration cache from it. | 961 // We got a map in register eax. Get the enumeration cache from it. |
| 1006 __ bind(&use_cache); | 962 __ bind(&use_cache); |
| 1007 __ LoadInstanceDescriptors(eax, ecx); | 963 __ LoadInstanceDescriptors(eax, ecx); |
| 1008 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); | 964 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
| 1009 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 965 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 1010 | 966 |
| 1011 // Set up the four remaining stack slots. | 967 // Set up the four remaining stack slots. |
| 1012 __ push(eax); // Map. | 968 __ push(eax); // Map. |
| 1013 __ push(edx); // Enumeration cache. | 969 __ push(edx); // Enumeration cache. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1026 __ j(above, &non_proxy); | 982 __ j(above, &non_proxy); |
| 1027 __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy | 983 __ mov(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy |
| 1028 __ bind(&non_proxy); | 984 __ bind(&non_proxy); |
| 1029 __ push(ebx); // Smi | 985 __ push(ebx); // Smi |
| 1030 __ push(eax); // Array | 986 __ push(eax); // Array |
| 1031 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 987 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
| 1032 __ push(eax); // Fixed array length (as smi). | 988 __ push(eax); // Fixed array length (as smi). |
| 1033 __ push(Immediate(Smi::FromInt(0))); // Initial index. | 989 __ push(Immediate(Smi::FromInt(0))); // Initial index. |
| 1034 | 990 |
| 1035 // Generate code for doing the condition check. | 991 // Generate code for doing the condition check. |
| 992 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); |
| 1036 __ bind(&loop); | 993 __ bind(&loop); |
| 1037 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. | 994 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. |
| 1038 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. | 995 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. |
| 1039 __ j(above_equal, loop_statement.break_label()); | 996 __ j(above_equal, loop_statement.break_label()); |
| 1040 | 997 |
| 1041 // Get the current entry of the array into register ebx. | 998 // Get the current entry of the array into register ebx. |
| 1042 __ mov(ebx, Operand(esp, 2 * kPointerSize)); | 999 __ mov(ebx, Operand(esp, 2 * kPointerSize)); |
| 1043 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); | 1000 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); |
| 1044 | 1001 |
| 1045 // Get the expected map from the stack or a smi in the | 1002 // Get the expected map from the stack or a smi in the |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1068 __ test(eax, eax); | 1025 __ test(eax, eax); |
| 1069 __ j(equal, loop_statement.continue_label()); | 1026 __ j(equal, loop_statement.continue_label()); |
| 1070 __ mov(ebx, eax); | 1027 __ mov(ebx, eax); |
| 1071 | 1028 |
| 1072 // Update the 'each' property or variable from the possibly filtered | 1029 // Update the 'each' property or variable from the possibly filtered |
| 1073 // entry in register ebx. | 1030 // entry in register ebx. |
| 1074 __ bind(&update_each); | 1031 __ bind(&update_each); |
| 1075 __ mov(result_register(), ebx); | 1032 __ mov(result_register(), ebx); |
| 1076 // Perform the assignment as if via '='. | 1033 // Perform the assignment as if via '='. |
| 1077 { EffectContext context(this); | 1034 { EffectContext context(this); |
| 1078 EmitAssignment(stmt->each(), stmt->AssignmentId()); | 1035 EmitAssignment(stmt->each()); |
| 1079 } | 1036 } |
| 1080 | 1037 |
| 1081 // Generate code for the body of the loop. | 1038 // Generate code for the body of the loop. |
| 1082 Visit(stmt->body()); | 1039 Visit(stmt->body()); |
| 1083 | 1040 |
| 1084 // Generate code for going to the next element by incrementing the | 1041 // Generate code for going to the next element by incrementing the |
| 1085 // index (smi) stored on top of the stack. | 1042 // index (smi) stored on top of the stack. |
| 1086 __ bind(loop_statement.continue_label()); | 1043 __ bind(loop_statement.continue_label()); |
| 1087 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); | 1044 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); |
| 1088 | 1045 |
| 1089 EmitStackCheck(stmt, &loop); | 1046 EmitStackCheck(stmt, &loop); |
| 1090 __ jmp(&loop); | 1047 __ jmp(&loop); |
| 1091 | 1048 |
| 1092 // Remove the pointers stored on the stack. | 1049 // Remove the pointers stored on the stack. |
| 1093 __ bind(loop_statement.break_label()); | 1050 __ bind(loop_statement.break_label()); |
| 1094 __ add(esp, Immediate(5 * kPointerSize)); | 1051 __ add(esp, Immediate(5 * kPointerSize)); |
| 1095 | 1052 |
| 1096 // Exit and decrement the loop depth. | 1053 // Exit and decrement the loop depth. |
| 1054 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 1097 __ bind(&exit); | 1055 __ bind(&exit); |
| 1098 decrement_loop_depth(); | 1056 decrement_loop_depth(); |
| 1099 } | 1057 } |
| 1100 | 1058 |
| 1101 | 1059 |
| 1102 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, | 1060 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, |
| 1103 bool pretenure) { | 1061 bool pretenure) { |
| 1104 // Use the fast case closure allocation code that allocates in new | 1062 // Use the fast case closure allocation code that allocates in new |
| 1105 // space for nested functions that don't need literals cloning. If | 1063 // space for nested functions that don't need literals cloning. If |
| 1106 // we're running with the --always-opt or the --prepare-always-opt | 1064 // 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) { | 1804 OverwriteMode mode) { |
| 1847 __ pop(edx); | 1805 __ pop(edx); |
| 1848 BinaryOpStub stub(op, mode); | 1806 BinaryOpStub stub(op, mode); |
| 1849 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. | 1807 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 1850 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); | 1808 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 1851 patch_site.EmitPatchInfo(); | 1809 patch_site.EmitPatchInfo(); |
| 1852 context()->Plug(eax); | 1810 context()->Plug(eax); |
| 1853 } | 1811 } |
| 1854 | 1812 |
| 1855 | 1813 |
| 1856 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1814 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
| 1857 // Invalid left-hand sides are rewritten to have a 'throw | 1815 // Invalid left-hand sides are rewritten to have a 'throw |
| 1858 // ReferenceError' on the left-hand side. | 1816 // ReferenceError' on the left-hand side. |
| 1859 if (!expr->IsValidLeftHandSide()) { | 1817 if (!expr->IsValidLeftHandSide()) { |
| 1860 VisitForEffect(expr); | 1818 VisitForEffect(expr); |
| 1861 return; | 1819 return; |
| 1862 } | 1820 } |
| 1863 | 1821 |
| 1864 // Left-hand side can only be a property, a global or a (parameter or local) | 1822 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1865 // slot. | 1823 // slot. |
| 1866 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1824 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1898 __ mov(ecx, eax); | 1856 __ mov(ecx, eax); |
| 1899 __ pop(edx); | 1857 __ pop(edx); |
| 1900 __ pop(eax); // Restore value. | 1858 __ pop(eax); // Restore value. |
| 1901 Handle<Code> ic = is_classic_mode() | 1859 Handle<Code> ic = is_classic_mode() |
| 1902 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 1860 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 1903 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 1861 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 1904 __ call(ic); | 1862 __ call(ic); |
| 1905 break; | 1863 break; |
| 1906 } | 1864 } |
| 1907 } | 1865 } |
| 1908 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | |
| 1909 context()->Plug(eax); | 1866 context()->Plug(eax); |
| 1910 } | 1867 } |
| 1911 | 1868 |
| 1912 | 1869 |
| 1913 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1870 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1914 Token::Value op) { | 1871 Token::Value op) { |
| 1915 if (var->IsUnallocated()) { | 1872 if (var->IsUnallocated()) { |
| 1916 // Global var, const, or let. | 1873 // Global var, const, or let. |
| 1917 __ mov(ecx, var->name()); | 1874 __ mov(ecx, var->name()); |
| 1918 __ mov(edx, GlobalObjectOperand()); | 1875 __ mov(edx, GlobalObjectOperand()); |
| (...skipping 2507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4426 *context_length = 0; | 4383 *context_length = 0; |
| 4427 return previous_; | 4384 return previous_; |
| 4428 } | 4385 } |
| 4429 | 4386 |
| 4430 | 4387 |
| 4431 #undef __ | 4388 #undef __ |
| 4432 | 4389 |
| 4433 } } // namespace v8::internal | 4390 } } // namespace v8::internal |
| 4434 | 4391 |
| 4435 #endif // V8_TARGET_ARCH_IA32 | 4392 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |