OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |