Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Side by Side Diff: src/ia32/full-codegen-ia32.cc

Issue 9425045: Support fast case for-in in Crankshaft. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: port to x64&arm, cleanup Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698