| 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 |