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

Side by Side Diff: src/ia32/stub-cache-ia32.cc

Issue 2801018: This change allows generating call-stubs for objects with normal (non-fast) o... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 5 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
« no previous file with comments | « src/ia32/macro-assembler-ia32.cc ('k') | src/ic.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag)); 94 __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag));
95 __ jmp(Operand(offset)); 95 __ jmp(Operand(offset));
96 96
97 // Pop at miss. 97 // Pop at miss.
98 __ bind(&miss); 98 __ bind(&miss);
99 __ pop(offset); 99 __ pop(offset);
100 } 100 }
101 } 101 }
102 102
103 103
104 // Helper function used to check that the dictionary doesn't contain
105 // the property. This function may return false negatives, so miss_label
106 // must always call a backup property check that is complete.
107 // This function is safe to call if the receiver has fast properties.
108 // Name must be a symbol and receiver must be a heap object.
109 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
110 Label* miss_label,
111 Register receiver,
112 String* name,
113 Register r0,
114 Register extra) {
115 ASSERT(name->IsSymbol());
116 __ IncrementCounter(&Counters::negative_lookups, 1);
117 __ IncrementCounter(&Counters::negative_lookups_miss, 1);
118
119 Label done;
120 __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
121
122 const int kInterceptorOrAccessCheckNeededMask =
123 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
124 // Bail out if the receiver has a named interceptor or requires access checks.
125 __ test(FieldOperand(r0, Map::kBitFieldOffset),
126 Immediate(kInterceptorOrAccessCheckNeededMask));
127 __ j(not_zero, miss_label, not_taken);
128
129 __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE);
130 __ j(below, miss_label, not_taken);
131
132 // Load properties array.
133 Register properties = r0;
134 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
135
136 // Check that the properties array is a dictionary.
137 __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
138 Immediate(Factory::hash_table_map()));
139 __ j(not_equal, miss_label);
140
141 // Compute the capacity mask.
142 const int kCapacityOffset =
143 StringDictionary::kHeaderSize +
144 StringDictionary::kCapacityIndex * kPointerSize;
145
146 // Generate an unrolled loop that performs a few probes before
147 // giving up.
148 static const int kProbes = 4;
149 const int kElementsStartOffset =
150 StringDictionary::kHeaderSize +
151 StringDictionary::kElementsStartIndex * kPointerSize;
152
153 // If names of slots in range from 1 to kProbes - 1 for the hash value are
154 // not equal to the name and kProbes-th slot is not used (its name is the
155 // undefined value), it guarantees the hash table doesn't contain the
156 // property. It's true even if some slots represent deleted properties
157 // (their names are the null value).
158 for (int i = 0; i < kProbes; i++) {
159 // r0 points to properties hash.
160 // Compute the masked index: (hash + i + i * i) & mask.
161 if (extra.is(no_reg)) {
162 __ push(receiver);
163 }
164 Register index = extra.is(no_reg) ? receiver : extra;
165 // Capacity is smi 2^n.
166 __ mov(index, FieldOperand(properties, kCapacityOffset));
167 __ dec(index);
168 __ and_(Operand(index),
169 Immediate(Smi::FromInt(name->Hash() +
170 StringDictionary::GetProbeOffset(i))));
171
172 // Scale the index by multiplying by the entry size.
173 ASSERT(StringDictionary::kEntrySize == 3);
174 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
175
176 Register entity_name = extra.is(no_reg) ? properties : extra;
177 // Having undefined at this place means the name is not contained.
178 ASSERT_EQ(kSmiTagSize, 1);
179 __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
180 kElementsStartOffset - kHeapObjectTag));
181 __ cmp(entity_name, Factory::undefined_value());
182 if (extra.is(no_reg)) {
183 // 'receiver' shares a register with 'entity_name'.
184 __ pop(receiver);
185 }
186 if (i != kProbes - 1) {
187 __ j(equal, &done, taken);
188
189 // Stop if found the property.
190 __ cmp(entity_name, Handle<String>(name));
191 __ j(equal, miss_label, not_taken);
192
193 if (extra.is(no_reg)) {
194 // Restore the properties if their register was occupied by the name.
195 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
196 }
197 } else {
198 // Give up probing if still not found the undefined value.
199 __ j(not_equal, miss_label, not_taken);
200 }
201 }
202
203 __ bind(&done);
204 __ DecrementCounter(&Counters::negative_lookups_miss, 1);
205 }
206
207
104 void StubCache::GenerateProbe(MacroAssembler* masm, 208 void StubCache::GenerateProbe(MacroAssembler* masm,
105 Code::Flags flags, 209 Code::Flags flags,
106 Register receiver, 210 Register receiver,
107 Register name, 211 Register name,
108 Register scratch, 212 Register scratch,
109 Register extra) { 213 Register extra) {
110 Label miss; 214 Label miss;
111 215
112 // Make sure that code is valid. The shifting code relies on the 216 // Make sure that code is valid. The shifting code relies on the
113 // entry size being 8. 217 // entry size being 8.
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after
716 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); 820 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
717 ASSERT(cell->value()->IsTheHole()); 821 ASSERT(cell->value()->IsTheHole());
718 __ mov(scratch, Immediate(Handle<Object>(cell))); 822 __ mov(scratch, Immediate(Handle<Object>(cell)));
719 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), 823 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
720 Immediate(Factory::the_hole_value())); 824 Immediate(Factory::the_hole_value()));
721 __ j(not_equal, miss, not_taken); 825 __ j(not_equal, miss, not_taken);
722 return cell; 826 return cell;
723 } 827 }
724 828
725 829
830 // Calls GenerateCheckPropertyCell for each global object in the prototype chain
831 // from object to (but not including) holder.
832 static Object* GenerateCheckPropertyCells(MacroAssembler* masm,
833 JSObject* object,
834 JSObject* holder,
835 String* name,
836 Register scratch,
837 Label* miss) {
838 JSObject* current = object;
839 while (current != holder) {
840 if (current->IsGlobalObject()) {
841 Object* cell = GenerateCheckPropertyCell(masm,
842 GlobalObject::cast(current),
843 name,
844 scratch,
845 miss);
846 if (cell->IsFailure()) {
847 return cell;
848 }
849 }
850 ASSERT(current->IsJSObject());
851 current = JSObject::cast(current->GetPrototype());
852 }
853 return NULL;
854 }
855
856
726 #undef __ 857 #undef __
727 #define __ ACCESS_MASM(masm()) 858 #define __ ACCESS_MASM(masm())
728 859
729 860
730 Register StubCompiler::CheckPrototypes(JSObject* object, 861 Register StubCompiler::CheckPrototypes(JSObject* object,
731 Register object_reg, 862 Register object_reg,
732 JSObject* holder, 863 JSObject* holder,
733 Register holder_reg, 864 Register holder_reg,
734 Register scratch, 865 Register scratch,
735 String* name, 866 String* name,
736 int push_at_depth, 867 int save_at_depth,
737 Label* miss) { 868 Label* miss,
738 // Check that the maps haven't changed. 869 Register extra) {
739 Register result = 870 // Make sure there's no overlap between holder and object registers.
740 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, 871 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
741 push_at_depth, miss); 872 ASSERT(!extra.is(object_reg) && !extra.is(holder_reg) && !extra.is(scratch));
873 // Keep track of the current object in register reg.
874 Register reg = object_reg;
875 JSObject* current = object;
876 int depth = 0;
877
878 if (save_at_depth == depth) {
879 __ mov(Operand(esp, kPointerSize), reg);
880 }
881
882 // Traverse the prototype chain and check the maps in the prototype chain for
883 // fast and global objects or do negative lookup for normal objects.
884 while (current != holder) {
885 depth++;
886
887 // Only global objects and objects that do not require access
888 // checks are allowed in stubs.
889 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
890
891 ASSERT(current->GetPrototype()->IsJSObject());
892 JSObject* prototype = JSObject::cast(current->GetPrototype());
893 if (!current->HasFastProperties() &&
894 !current->IsJSGlobalObject() &&
895 !current->IsJSGlobalProxy()) {
896 if (!name->IsSymbol()) {
897 Object* lookup_result = Heap::LookupSymbol(name);
898 if (lookup_result->IsFailure()) {
899 set_failure(Failure::cast(lookup_result));
900 return reg;
901 } else {
902 name = String::cast(lookup_result);
903 }
904 }
905 ASSERT(current->property_dictionary()->FindEntry(name) ==
906 StringDictionary::kNotFound);
907
908 GenerateDictionaryNegativeLookup(masm(),
909 miss,
910 reg,
911 name,
912 scratch,
913 extra);
914 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
915 reg = holder_reg; // from now the object is in holder_reg
916 __ mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
917 } else if (Heap::InNewSpace(prototype)) {
918 // Get the map of the current object.
919 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
920 __ cmp(Operand(scratch), Immediate(Handle<Map>(current->map())));
921 // Branch on the result of the map check.
922 __ j(not_equal, miss, not_taken);
923 // Check access rights to the global object. This has to happen
924 // after the map check so that we know that the object is
925 // actually a global object.
926 if (current->IsJSGlobalProxy()) {
927 __ CheckAccessGlobalProxy(reg, scratch, miss);
928
929 // Restore scratch register to be the map of the object.
930 // We load the prototype from the map in the scratch register.
931 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
932 }
933 // The prototype is in new space; we cannot store a reference
934 // to it in the code. Load it from the map.
935 reg = holder_reg; // from now the object is in holder_reg
936 __ mov(reg, FieldOperand(scratch, Map::kPrototypeOffset));
937 } else {
938 // Check the map of the current object.
939 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
940 Immediate(Handle<Map>(current->map())));
941 // Branch on the result of the map check.
942 __ j(not_equal, miss, not_taken);
943 // Check access rights to the global object. This has to happen
944 // after the map check so that we know that the object is
945 // actually a global object.
946 if (current->IsJSGlobalProxy()) {
947 __ CheckAccessGlobalProxy(reg, scratch, miss);
948 }
949 // The prototype is in old space; load it directly.
950 reg = holder_reg; // from now the object is in holder_reg
951 __ mov(reg, Handle<JSObject>(prototype));
952 }
953
954 if (save_at_depth == depth) {
955 __ mov(Operand(esp, kPointerSize), reg);
956 }
957
958 // Go to the next object in the prototype chain.
959 current = prototype;
960 }
961 ASSERT(current == holder);
962
963 // Log the check depth.
964 LOG(IntEvent("check-maps-depth", depth + 1));
965
966 // Check the holder map.
967 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
968 Immediate(Handle<Map>(holder->map())));
969 __ j(not_equal, miss, not_taken);
970
971 // Perform security check for access to the global object.
972 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
973 if (holder->IsJSGlobalProxy()) {
974 __ CheckAccessGlobalProxy(reg, scratch, miss);
975 };
742 976
743 // If we've skipped any global objects, it's not enough to verify 977 // If we've skipped any global objects, it's not enough to verify
744 // that their maps haven't changed. We also need to check that the 978 // that their maps haven't changed. We also need to check that the
745 // property cell for the property is still empty. 979 // property cell for the property is still empty.
746 while (object != holder) { 980 Object* result = GenerateCheckPropertyCells(masm(),
747 if (object->IsGlobalObject()) { 981 object,
748 Object* cell = GenerateCheckPropertyCell(masm(), 982 holder,
749 GlobalObject::cast(object), 983 name,
750 name, 984 scratch,
751 scratch, 985 miss);
752 miss); 986 if (result->IsFailure()) set_failure(Failure::cast(result));
753 if (cell->IsFailure()) {
754 set_failure(Failure::cast(cell));
755 return result;
756 }
757 }
758 object = JSObject::cast(object->GetPrototype());
759 }
760 987
761 // Return the register containing the holder. 988 // Return the register containing the holder.
762 return result; 989 return reg;
763 } 990 }
764 991
765 992
766 void StubCompiler::GenerateLoadField(JSObject* object, 993 void StubCompiler::GenerateLoadField(JSObject* object,
767 JSObject* holder, 994 JSObject* holder,
768 Register receiver, 995 Register receiver,
769 Register scratch1, 996 Register scratch1,
770 Register scratch2, 997 Register scratch2,
771 int index, 998 int index,
772 String* name, 999 String* name,
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
1076 1303
1077 // Get the receiver from the stack. 1304 // Get the receiver from the stack.
1078 const int argc = arguments().immediate(); 1305 const int argc = arguments().immediate();
1079 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1306 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1080 1307
1081 // Check that the receiver isn't a smi. 1308 // Check that the receiver isn't a smi.
1082 __ test(edx, Immediate(kSmiTagMask)); 1309 __ test(edx, Immediate(kSmiTagMask));
1083 __ j(zero, &miss, not_taken); 1310 __ j(zero, &miss, not_taken);
1084 1311
1085 // Do the right check and compute the holder register. 1312 // Do the right check and compute the holder register.
1086 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, name, &miss); 1313 Register reg = CheckPrototypes(object, edx, holder, ebx, eax,
1314 name, &miss, edi);
1087 1315
1088 GenerateFastPropertyLoad(masm(), edi, reg, holder, index); 1316 GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
1089 1317
1090 // Check that the function really is a function. 1318 // Check that the function really is a function.
1091 __ test(edi, Immediate(kSmiTagMask)); 1319 __ test(edi, Immediate(kSmiTagMask));
1092 __ j(zero, &miss, not_taken); 1320 __ j(zero, &miss, not_taken);
1093 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); 1321 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
1094 __ j(not_equal, &miss, not_taken); 1322 __ j(not_equal, &miss, not_taken);
1095 1323
1096 // Patch the receiver on the stack with the global proxy if 1324 // Patch the receiver on the stack with the global proxy if
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1138 // Get the receiver from the stack. 1366 // Get the receiver from the stack.
1139 const int argc = arguments().immediate(); 1367 const int argc = arguments().immediate();
1140 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1368 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1141 1369
1142 // Check that the receiver isn't a smi. 1370 // Check that the receiver isn't a smi.
1143 __ test(edx, Immediate(kSmiTagMask)); 1371 __ test(edx, Immediate(kSmiTagMask));
1144 __ j(zero, &miss); 1372 __ j(zero, &miss);
1145 1373
1146 CheckPrototypes(JSObject::cast(object), edx, 1374 CheckPrototypes(JSObject::cast(object), edx,
1147 holder, ebx, 1375 holder, ebx,
1148 eax, name, &miss); 1376 eax, name, &miss, edi);
1149 1377
1150 if (argc == 0) { 1378 if (argc == 0) {
1151 // Noop, return the length. 1379 // Noop, return the length.
1152 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); 1380 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
1153 __ ret((argc + 1) * kPointerSize); 1381 __ ret((argc + 1) * kPointerSize);
1154 } else { 1382 } else {
1155 // Get the elements array of the object. 1383 // Get the elements array of the object.
1156 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); 1384 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
1157 1385
1158 // Check that the elements are in fast mode (not dictionary). 1386 // Check that the elements are in fast mode (not dictionary).
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
1284 1512
1285 // Get the receiver from the stack. 1513 // Get the receiver from the stack.
1286 const int argc = arguments().immediate(); 1514 const int argc = arguments().immediate();
1287 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 1515 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1288 1516
1289 // Check that the receiver isn't a smi. 1517 // Check that the receiver isn't a smi.
1290 __ test(edx, Immediate(kSmiTagMask)); 1518 __ test(edx, Immediate(kSmiTagMask));
1291 __ j(zero, &miss); 1519 __ j(zero, &miss);
1292 CheckPrototypes(JSObject::cast(object), edx, 1520 CheckPrototypes(JSObject::cast(object), edx,
1293 holder, ebx, 1521 holder, ebx,
1294 eax, name, &miss); 1522 eax, name, &miss, edi);
1295 1523
1296 // Get the elements array of the object. 1524 // Get the elements array of the object.
1297 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); 1525 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
1298 1526
1299 // Check that the elements are in fast mode (not dictionary). 1527 // Check that the elements are in fast mode (not dictionary).
1300 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 1528 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1301 Immediate(Factory::fixed_array_map())); 1529 Immediate(Factory::fixed_array_map()));
1302 __ j(not_equal, &miss); 1530 __ j(not_equal, &miss);
1303 1531
1304 // Get the array's length into ecx and calculate new length. 1532 // Get the array's length into ecx and calculate new length.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1359 1587
1360 Label miss; 1588 Label miss;
1361 Label index_out_of_range; 1589 Label index_out_of_range;
1362 GenerateNameCheck(name, &miss); 1590 GenerateNameCheck(name, &miss);
1363 1591
1364 // Check that the maps starting from the prototype haven't changed. 1592 // Check that the maps starting from the prototype haven't changed.
1365 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1593 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1366 Context::STRING_FUNCTION_INDEX, 1594 Context::STRING_FUNCTION_INDEX,
1367 eax); 1595 eax);
1368 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, 1596 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
1369 ebx, edx, name, &miss); 1597 ebx, edx, name, &miss, edi);
1370 1598
1371 Register receiver = ebx; 1599 Register receiver = ebx;
1372 Register index = edi; 1600 Register index = edi;
1373 Register scratch = edx; 1601 Register scratch = edx;
1374 Register result = eax; 1602 Register result = eax;
1375 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); 1603 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1376 if (argc > 0) { 1604 if (argc > 0) {
1377 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); 1605 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1378 } else { 1606 } else {
1379 __ Set(index, Immediate(Factory::undefined_value())); 1607 __ Set(index, Immediate(Factory::undefined_value()));
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1424 Label miss; 1652 Label miss;
1425 Label index_out_of_range; 1653 Label index_out_of_range;
1426 1654
1427 GenerateNameCheck(name, &miss); 1655 GenerateNameCheck(name, &miss);
1428 1656
1429 // Check that the maps starting from the prototype haven't changed. 1657 // Check that the maps starting from the prototype haven't changed.
1430 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1658 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1431 Context::STRING_FUNCTION_INDEX, 1659 Context::STRING_FUNCTION_INDEX,
1432 eax); 1660 eax);
1433 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, 1661 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
1434 ebx, edx, name, &miss); 1662 ebx, edx, name, &miss, edi);
1435 1663
1436 Register receiver = eax; 1664 Register receiver = eax;
1437 Register index = edi; 1665 Register index = edi;
1438 Register scratch1 = ebx; 1666 Register scratch1 = ebx;
1439 Register scratch2 = edx; 1667 Register scratch2 = edx;
1440 Register result = eax; 1668 Register result = eax;
1441 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); 1669 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1442 if (argc > 0) { 1670 if (argc > 0) {
1443 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); 1671 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1444 } else { 1672 } else {
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1529 JSObject::cast(object), holder); 1757 JSObject::cast(object), holder);
1530 } 1758 }
1531 1759
1532 if (depth != kInvalidProtoDepth) { 1760 if (depth != kInvalidProtoDepth) {
1533 __ IncrementCounter(&Counters::call_const_fast_api, 1); 1761 __ IncrementCounter(&Counters::call_const_fast_api, 1);
1534 ReserveSpaceForFastApiCall(masm(), eax); 1762 ReserveSpaceForFastApiCall(masm(), eax);
1535 } 1763 }
1536 1764
1537 // Check that the maps haven't changed. 1765 // Check that the maps haven't changed.
1538 CheckPrototypes(JSObject::cast(object), edx, holder, 1766 CheckPrototypes(JSObject::cast(object), edx, holder,
1539 ebx, eax, name, depth, &miss); 1767 ebx, eax, name, depth, &miss, edi);
1540 1768
1541 // Patch the receiver on the stack with the global proxy if 1769 // Patch the receiver on the stack with the global proxy if
1542 // necessary. 1770 // necessary.
1543 if (object->IsGlobalObject()) { 1771 if (object->IsGlobalObject()) {
1544 ASSERT(depth == kInvalidProtoDepth); 1772 ASSERT(depth == kInvalidProtoDepth);
1545 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); 1773 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1546 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); 1774 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1547 } 1775 }
1548 break; 1776 break;
1549 1777
1550 case STRING_CHECK: 1778 case STRING_CHECK:
1551 if (!function->IsBuiltin()) { 1779 if (!function->IsBuiltin()) {
1552 // Calling non-builtins with a value as receiver requires boxing. 1780 // Calling non-builtins with a value as receiver requires boxing.
1553 __ jmp(&miss); 1781 __ jmp(&miss);
1554 } else { 1782 } else {
1555 // Check that the object is a string or a symbol. 1783 // Check that the object is a string or a symbol.
1556 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax); 1784 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
1557 __ j(above_equal, &miss, not_taken); 1785 __ j(above_equal, &miss, not_taken);
1558 // Check that the maps starting from the prototype haven't changed. 1786 // Check that the maps starting from the prototype haven't changed.
1559 GenerateDirectLoadGlobalFunctionPrototype( 1787 GenerateDirectLoadGlobalFunctionPrototype(
1560 masm(), Context::STRING_FUNCTION_INDEX, eax); 1788 masm(), Context::STRING_FUNCTION_INDEX, eax);
1561 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, 1789 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
1562 ebx, edx, name, &miss); 1790 ebx, edx, name, &miss, edi);
1563 } 1791 }
1564 break; 1792 break;
1565 1793
1566 case NUMBER_CHECK: { 1794 case NUMBER_CHECK: {
1567 if (!function->IsBuiltin()) { 1795 if (!function->IsBuiltin()) {
1568 // Calling non-builtins with a value as receiver requires boxing. 1796 // Calling non-builtins with a value as receiver requires boxing.
1569 __ jmp(&miss); 1797 __ jmp(&miss);
1570 } else { 1798 } else {
1571 Label fast; 1799 Label fast;
1572 // Check that the object is a smi or a heap number. 1800 // Check that the object is a smi or a heap number.
1573 __ test(edx, Immediate(kSmiTagMask)); 1801 __ test(edx, Immediate(kSmiTagMask));
1574 __ j(zero, &fast, taken); 1802 __ j(zero, &fast, taken);
1575 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); 1803 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax);
1576 __ j(not_equal, &miss, not_taken); 1804 __ j(not_equal, &miss, not_taken);
1577 __ bind(&fast); 1805 __ bind(&fast);
1578 // Check that the maps starting from the prototype haven't changed. 1806 // Check that the maps starting from the prototype haven't changed.
1579 GenerateDirectLoadGlobalFunctionPrototype( 1807 GenerateDirectLoadGlobalFunctionPrototype(
1580 masm(), Context::NUMBER_FUNCTION_INDEX, eax); 1808 masm(), Context::NUMBER_FUNCTION_INDEX, eax);
1581 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, 1809 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
1582 ebx, edx, name, &miss); 1810 ebx, edx, name, &miss, edi);
1583 } 1811 }
1584 break; 1812 break;
1585 } 1813 }
1586 1814
1587 case BOOLEAN_CHECK: { 1815 case BOOLEAN_CHECK: {
1588 if (!function->IsBuiltin()) { 1816 if (!function->IsBuiltin()) {
1589 // Calling non-builtins with a value as receiver requires boxing. 1817 // Calling non-builtins with a value as receiver requires boxing.
1590 __ jmp(&miss); 1818 __ jmp(&miss);
1591 } else { 1819 } else {
1592 Label fast; 1820 Label fast;
1593 // Check that the object is a boolean. 1821 // Check that the object is a boolean.
1594 __ cmp(edx, Factory::true_value()); 1822 __ cmp(edx, Factory::true_value());
1595 __ j(equal, &fast, taken); 1823 __ j(equal, &fast, taken);
1596 __ cmp(edx, Factory::false_value()); 1824 __ cmp(edx, Factory::false_value());
1597 __ j(not_equal, &miss, not_taken); 1825 __ j(not_equal, &miss, not_taken);
1598 __ bind(&fast); 1826 __ bind(&fast);
1599 // Check that the maps starting from the prototype haven't changed. 1827 // Check that the maps starting from the prototype haven't changed.
1600 GenerateDirectLoadGlobalFunctionPrototype( 1828 GenerateDirectLoadGlobalFunctionPrototype(
1601 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax); 1829 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax);
1602 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, 1830 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
1603 ebx, edx, name, &miss); 1831 ebx, edx, name, &miss, edi);
1604 } 1832 }
1605 break; 1833 break;
1606 } 1834 }
1607 1835
1608 default: 1836 default:
1609 UNREACHABLE(); 1837 UNREACHABLE();
1610 } 1838 }
1611 1839
1612 if (depth != kInvalidProtoDepth) { 1840 if (depth != kInvalidProtoDepth) {
1613 GenerateFastApiCall(masm(), optimization, argc); 1841 GenerateFastApiCall(masm(), optimization, argc);
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1715 1943
1716 // If the object is the holder then we know that it's a global 1944 // If the object is the holder then we know that it's a global
1717 // object which can only happen for contextual calls. In this case, 1945 // object which can only happen for contextual calls. In this case,
1718 // the receiver cannot be a smi. 1946 // the receiver cannot be a smi.
1719 if (object != holder) { 1947 if (object != holder) {
1720 __ test(edx, Immediate(kSmiTagMask)); 1948 __ test(edx, Immediate(kSmiTagMask));
1721 __ j(zero, &miss, not_taken); 1949 __ j(zero, &miss, not_taken);
1722 } 1950 }
1723 1951
1724 // Check that the maps haven't changed. 1952 // Check that the maps haven't changed.
1725 CheckPrototypes(object, edx, holder, ebx, eax, name, &miss); 1953 CheckPrototypes(object, edx, holder, ebx, eax, name, &miss, edi);
1726 1954
1727 // Get the value from the cell. 1955 // Get the value from the cell.
1728 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); 1956 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
1729 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset)); 1957 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
1730 1958
1731 // Check that the cell contains the same function. 1959 // Check that the cell contains the same function.
1732 if (Heap::InNewSpace(function)) { 1960 if (Heap::InNewSpace(function)) {
1733 // We can't embed a pointer to a function in new space so we have 1961 // We can't embed a pointer to a function in new space so we have
1734 // to verify that the shared function info is unchanged. This has 1962 // to verify that the shared function info is unchanged. This has
1735 // the nice side effect that multiple closures based on the same 1963 // the nice side effect that multiple closures based on the same
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
1986 // -- eax : receiver 2214 // -- eax : receiver
1987 // -- ecx : name 2215 // -- ecx : name
1988 // -- esp[0] : return address 2216 // -- esp[0] : return address
1989 // ----------------------------------- 2217 // -----------------------------------
1990 Label miss; 2218 Label miss;
1991 2219
1992 // Check that the receiver isn't a smi. 2220 // Check that the receiver isn't a smi.
1993 __ test(eax, Immediate(kSmiTagMask)); 2221 __ test(eax, Immediate(kSmiTagMask));
1994 __ j(zero, &miss, not_taken); 2222 __ j(zero, &miss, not_taken);
1995 2223
2224 ASSERT(last->IsGlobalObject() || last->HasFastProperties());
2225
1996 // Check the maps of the full prototype chain. Also check that 2226 // Check the maps of the full prototype chain. Also check that
1997 // global property cells up to (but not including) the last object 2227 // global property cells up to (but not including) the last object
1998 // in the prototype chain are empty. 2228 // in the prototype chain are empty.
1999 CheckPrototypes(object, eax, last, ebx, edx, name, &miss); 2229 CheckPrototypes(object, eax, last, ebx, edx, name, &miss);
2000 2230
2001 // If the last object in the prototype chain is a global object, 2231 // If the last object in the prototype chain is a global object,
2002 // check that the global property cell is empty. 2232 // check that the global property cell is empty.
2003 if (last->IsGlobalObject()) { 2233 if (last->IsGlobalObject()) {
2004 Object* cell = GenerateCheckPropertyCell(masm(), 2234 Object* cell = GenerateCheckPropertyCell(masm(),
2005 GlobalObject::cast(last), 2235 GlobalObject::cast(last),
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
2133 2363
2134 // If the object is the holder then we know that it's a global 2364 // If the object is the holder then we know that it's a global
2135 // object which can only happen for contextual loads. In this case, 2365 // object which can only happen for contextual loads. In this case,
2136 // the receiver cannot be a smi. 2366 // the receiver cannot be a smi.
2137 if (object != holder) { 2367 if (object != holder) {
2138 __ test(eax, Immediate(kSmiTagMask)); 2368 __ test(eax, Immediate(kSmiTagMask));
2139 __ j(zero, &miss, not_taken); 2369 __ j(zero, &miss, not_taken);
2140 } 2370 }
2141 2371
2142 // Check that the maps haven't changed. 2372 // Check that the maps haven't changed.
2143 CheckPrototypes(object, eax, holder, ebx, edx, name, &miss); 2373 CheckPrototypes(object, eax, holder, ebx, edx, name, &miss, edi);
2144 2374
2145 // Get the value from the cell. 2375 // Get the value from the cell.
2146 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); 2376 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
2147 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); 2377 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
2148 2378
2149 // Check for deleted property if property can actually be deleted. 2379 // Check for deleted property if property can actually be deleted.
2150 if (!is_dont_delete) { 2380 if (!is_dont_delete) {
2151 __ cmp(ebx, Factory::the_hole_value()); 2381 __ cmp(ebx, Factory::the_hole_value());
2152 __ j(equal, &miss, not_taken); 2382 __ j(equal, &miss, not_taken);
2153 } else if (FLAG_debug_code) { 2383 } else if (FLAG_debug_code) {
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after
2500 // Return the generated code. 2730 // Return the generated code.
2501 return GetCode(); 2731 return GetCode();
2502 } 2732 }
2503 2733
2504 2734
2505 #undef __ 2735 #undef __
2506 2736
2507 } } // namespace v8::internal 2737 } } // namespace v8::internal
2508 2738
2509 #endif // V8_TARGET_ARCH_IA32 2739 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/ia32/macro-assembler-ia32.cc ('k') | src/ic.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698