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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 // Jump to the first instruction in the code stub. | 76 // Jump to the first instruction in the code stub. |
77 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag)); | 77 __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag)); |
78 __ Jump(offset); | 78 __ Jump(offset); |
79 | 79 |
80 // Miss: Restore offset and fall through. | 80 // Miss: Restore offset and fall through. |
81 __ bind(&miss); | 81 __ bind(&miss); |
82 __ pop(offset); | 82 __ pop(offset); |
83 } | 83 } |
84 | 84 |
85 | 85 |
| 86 // Helper function used to check that the dictionary doesn't contain |
| 87 // the property. This function may return false negatives, so miss_label |
| 88 // must always call a backup property check that is complete. |
| 89 // This function is safe to call if the receiver has fast properties. |
| 90 // Name must be a symbol and receiver must be a heap object. |
| 91 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, |
| 92 Label* miss_label, |
| 93 Register receiver, |
| 94 String* name, |
| 95 Register r0, |
| 96 Register extra) { |
| 97 ASSERT(name->IsSymbol()); |
| 98 if (!extra.is(no_reg)) { |
| 99 __ IncrementCounter(&Counters::negative_lookups, 1, r0, extra); |
| 100 __ IncrementCounter(&Counters::negative_lookups_miss, 1, r0, extra); |
| 101 } |
| 102 |
| 103 Label done; |
| 104 |
| 105 const int kInterceptorOrAccessCheckNeededMask = |
| 106 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
| 107 |
| 108 // Bail out if the receiver has a named interceptor or requires access checks. |
| 109 Register map = extra.is(no_reg) ? r0 : extra; |
| 110 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 111 __ ldrb(r0, FieldMemOperand(map, Map::kBitFieldOffset)); |
| 112 __ tst(r0, Operand(kInterceptorOrAccessCheckNeededMask)); |
| 113 __ b(ne, miss_label); |
| 114 |
| 115 // Check that receiver is a JSObject. |
| 116 if (extra.is(no_reg)) { |
| 117 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 118 } |
| 119 __ ldrb(r0, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 120 __ cmp(r0, Operand(FIRST_JS_OBJECT_TYPE)); |
| 121 __ b(lt, miss_label); |
| 122 |
| 123 // Load properties array. |
| 124 Register properties = r0; |
| 125 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 126 // Check that the properties array is a dictionary. |
| 127 if (!extra.is(no_reg)) { |
| 128 __ ldr(extra, FieldMemOperand(properties, HeapObject::kMapOffset)); |
| 129 Register tmp = properties; |
| 130 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); |
| 131 __ cmp(extra, tmp); |
| 132 } else { |
| 133 Register tmp1 = receiver; |
| 134 Register tmp2 = properties; |
| 135 __ push(tmp1); |
| 136 __ ldr(tmp1, FieldMemOperand(properties, HeapObject::kMapOffset)); |
| 137 __ LoadRoot(tmp2, Heap::kHashTableMapRootIndex); |
| 138 __ cmp(tmp1, tmp2); |
| 139 __ pop(tmp1); |
| 140 } |
| 141 __ b(ne, miss_label); |
| 142 |
| 143 // Restore the temporarily used register. |
| 144 __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 145 |
| 146 // Compute the capacity mask. |
| 147 const int kCapacityOffset = |
| 148 StringDictionary::kHeaderSize + |
| 149 StringDictionary::kCapacityIndex * kPointerSize; |
| 150 |
| 151 // Generate an unrolled loop that performs a few probes before |
| 152 // giving up. |
| 153 static const int kProbes = 4; |
| 154 const int kElementsStartOffset = |
| 155 StringDictionary::kHeaderSize + |
| 156 StringDictionary::kElementsStartIndex * kPointerSize; |
| 157 |
| 158 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 159 // not equal to the name and kProbes-th slot is not used (its name is the |
| 160 // undefined value), it guarantees the hash table doesn't contain the |
| 161 // property. It's true even if some slots represent deleted properties |
| 162 // (their names are the null value). |
| 163 for (int i = 0; i < kProbes; i++) { |
| 164 // r0 points to properties hash. |
| 165 // Compute the masked index: (hash + i + i * i) & mask. |
| 166 if (extra.is(no_reg)) { |
| 167 __ push(receiver); |
| 168 } |
| 169 Register index = extra.is(no_reg) ? receiver : extra; |
| 170 // Capacity is smi 2^n. |
| 171 __ ldr(index, FieldMemOperand(properties, kCapacityOffset)); |
| 172 __ sub(index, index, Operand(1)); |
| 173 __ and_(index, index, Operand( |
| 174 Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i)))); |
| 175 |
| 176 // Scale the index by multiplying by the entry size. |
| 177 ASSERT(StringDictionary::kEntrySize == 3); |
| 178 __ add(index, index, Operand(index, LSL, 1)); // index *= 3. |
| 179 |
| 180 Register entity_name = extra.is(no_reg) ? properties : extra; |
| 181 // Having undefined at this place means the name is not contained. |
| 182 ASSERT_EQ(kSmiTagSize, 1); |
| 183 Register tmp = extra.is(no_reg) ? receiver : properties; |
| 184 __ add(tmp, properties, Operand(index, LSL, 1)); |
| 185 __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset)); |
| 186 |
| 187 ASSERT(!tmp.is(entity_name)); |
| 188 __ LoadRoot(tmp, Heap::kUndefinedValueRootIndex); |
| 189 __ cmp(entity_name, tmp); |
| 190 if (extra.is(no_reg)) { |
| 191 // 'receiver' shares a register with 'entity_name'. |
| 192 __ pop(receiver); |
| 193 } |
| 194 if (i != kProbes - 1) { |
| 195 __ b(eq, &done); |
| 196 |
| 197 // Stop if found the property. |
| 198 __ cmp(entity_name, Operand(Handle<String>(name))); |
| 199 __ b(eq, miss_label); |
| 200 |
| 201 // Restore the properties. |
| 202 __ ldr(properties, |
| 203 FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 204 } else { |
| 205 // Give up probing if still not found the undefined value. |
| 206 __ b(ne, miss_label); |
| 207 } |
| 208 } |
| 209 __ bind(&done); |
| 210 if (!extra.is(no_reg)) { |
| 211 __ DecrementCounter(&Counters::negative_lookups_miss, 1, r0, extra); |
| 212 } |
| 213 } |
| 214 |
| 215 |
86 void StubCache::GenerateProbe(MacroAssembler* masm, | 216 void StubCache::GenerateProbe(MacroAssembler* masm, |
87 Code::Flags flags, | 217 Code::Flags flags, |
88 Register receiver, | 218 Register receiver, |
89 Register name, | 219 Register name, |
90 Register scratch, | 220 Register scratch, |
91 Register extra) { | 221 Register extra) { |
92 Label miss; | 222 Label miss; |
93 | 223 |
94 // Make sure that code is valid. The shifting code relies on the | 224 // Make sure that code is valid. The shifting code relies on the |
95 // entry size being 8. | 225 // entry size being 8. |
(...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 | 866 |
737 Register StubCompiler::CheckPrototypes(JSObject* object, | 867 Register StubCompiler::CheckPrototypes(JSObject* object, |
738 Register object_reg, | 868 Register object_reg, |
739 JSObject* holder, | 869 JSObject* holder, |
740 Register holder_reg, | 870 Register holder_reg, |
741 Register scratch, | 871 Register scratch, |
742 String* name, | 872 String* name, |
743 int save_at_depth, | 873 int save_at_depth, |
744 Label* miss, | 874 Label* miss, |
745 Register extra) { | 875 Register extra) { |
746 // Check that the maps haven't changed. | 876 // Make sure there's no overlap between scratch and the other |
747 Register result = | 877 // registers. |
748 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, | 878 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg)); |
749 save_at_depth, miss); | 879 |
| 880 // Keep track of the current object in register reg. |
| 881 Register reg = object_reg; |
| 882 int depth = 0; |
| 883 |
| 884 if (save_at_depth == depth) { |
| 885 __ str(reg, MemOperand(sp)); |
| 886 } |
| 887 |
| 888 // Check the maps in the prototype chain. |
| 889 // Traverse the prototype chain from the object and do map checks. |
| 890 JSObject* current = object; |
| 891 while (current != holder) { |
| 892 depth++; |
| 893 |
| 894 // Only global objects and objects that do not require access |
| 895 // checks are allowed in stubs. |
| 896 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); |
| 897 |
| 898 JSObject* prototype = JSObject::cast(current->GetPrototype()); |
| 899 if (!current->HasFastProperties() && |
| 900 !current->IsJSGlobalObject() && |
| 901 !current->IsJSGlobalProxy()) { |
| 902 if (!name->IsSymbol()) { |
| 903 Object* lookup_result = Heap::LookupSymbol(name); |
| 904 if (lookup_result->IsFailure()) { |
| 905 set_failure(Failure::cast(lookup_result)); |
| 906 return reg; |
| 907 } else { |
| 908 name = String::cast(lookup_result); |
| 909 } |
| 910 } |
| 911 ASSERT(current->property_dictionary()->FindEntry(name) == |
| 912 StringDictionary::kNotFound); |
| 913 |
| 914 GenerateDictionaryNegativeLookup(masm(), |
| 915 miss, |
| 916 reg, |
| 917 name, |
| 918 scratch, |
| 919 extra); |
| 920 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 921 reg = holder_reg; // from now the object is in holder_reg |
| 922 __ ldr(reg, FieldMemOperand(scratch, Map::kPrototypeOffset)); |
| 923 } else { |
| 924 // Get the map of the current object. |
| 925 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 926 __ cmp(scratch, Operand(Handle<Map>(current->map()))); |
| 927 |
| 928 // Branch on the result of the map check. |
| 929 __ b(ne, miss); |
| 930 |
| 931 // Check access rights to the global object. This has to happen |
| 932 // after the map check so that we know that the object is |
| 933 // actually a global object. |
| 934 if (current->IsJSGlobalProxy()) { |
| 935 __ CheckAccessGlobalProxy(reg, scratch, miss); |
| 936 // Restore scratch register to be the map of the object. In the |
| 937 // new space case below, we load the prototype from the map in |
| 938 // the scratch register. |
| 939 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 940 } |
| 941 |
| 942 reg = holder_reg; // from now the object is in holder_reg |
| 943 if (Heap::InNewSpace(prototype)) { |
| 944 // The prototype is in new space; we cannot store a reference |
| 945 // to it in the code. Load it from the map. |
| 946 __ ldr(reg, FieldMemOperand(scratch, Map::kPrototypeOffset)); |
| 947 } else { |
| 948 // The prototype is in old space; load it directly. |
| 949 __ mov(reg, Operand(Handle<JSObject>(prototype))); |
| 950 } |
| 951 } |
| 952 |
| 953 if (save_at_depth == depth) { |
| 954 __ str(reg, MemOperand(sp)); |
| 955 } |
| 956 |
| 957 // Go to the next object in the prototype chain. |
| 958 current = prototype; |
| 959 } |
| 960 |
| 961 // Check the holder map. |
| 962 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 963 __ cmp(scratch, Operand(Handle<Map>(current->map()))); |
| 964 __ b(ne, miss); |
| 965 |
| 966 // Log the check depth. |
| 967 LOG(IntEvent("check-maps-depth", depth + 1)); |
| 968 |
| 969 // Perform security check for access to the global object and return |
| 970 // the holder register. |
| 971 ASSERT(current == holder); |
| 972 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); |
| 973 if (current->IsJSGlobalProxy()) { |
| 974 __ CheckAccessGlobalProxy(reg, scratch, miss); |
| 975 } |
750 | 976 |
751 // 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 |
752 // 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 |
753 // property cell for the property is still empty. | 979 // property cell for the property is still empty. |
754 while (object != holder) { | 980 current = object; |
755 if (object->IsGlobalObject()) { | 981 while (current != holder) { |
| 982 if (current->IsGlobalObject()) { |
756 Object* cell = GenerateCheckPropertyCell(masm(), | 983 Object* cell = GenerateCheckPropertyCell(masm(), |
757 GlobalObject::cast(object), | 984 GlobalObject::cast(current), |
758 name, | 985 name, |
759 scratch, | 986 scratch, |
760 miss); | 987 miss); |
761 if (cell->IsFailure()) { | 988 if (cell->IsFailure()) { |
762 set_failure(Failure::cast(cell)); | 989 set_failure(Failure::cast(cell)); |
763 return result; | 990 return reg; |
764 } | 991 } |
765 } | 992 } |
766 object = JSObject::cast(object->GetPrototype()); | 993 current = JSObject::cast(current->GetPrototype()); |
767 } | 994 } |
768 | 995 |
769 // Return the register containing the holder. | 996 // Return the register containing the holder. |
770 return result; | 997 return reg; |
771 } | 998 } |
772 | 999 |
773 | 1000 |
774 void StubCompiler::GenerateLoadField(JSObject* object, | 1001 void StubCompiler::GenerateLoadField(JSObject* object, |
775 JSObject* holder, | 1002 JSObject* holder, |
776 Register receiver, | 1003 Register receiver, |
777 Register scratch1, | 1004 Register scratch1, |
778 Register scratch2, | 1005 Register scratch2, |
779 int index, | 1006 int index, |
780 String* name, | 1007 String* name, |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1046 | 1273 |
1047 const int argc = arguments().immediate(); | 1274 const int argc = arguments().immediate(); |
1048 | 1275 |
1049 // Get the receiver of the function from the stack into r0. | 1276 // Get the receiver of the function from the stack into r0. |
1050 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | 1277 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); |
1051 // Check that the receiver isn't a smi. | 1278 // Check that the receiver isn't a smi. |
1052 __ tst(r0, Operand(kSmiTagMask)); | 1279 __ tst(r0, Operand(kSmiTagMask)); |
1053 __ b(eq, &miss); | 1280 __ b(eq, &miss); |
1054 | 1281 |
1055 // Do the right check and compute the holder register. | 1282 // Do the right check and compute the holder register. |
1056 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss); | 1283 Register reg = CheckPrototypes(object, r0, holder, r1, r3, name, &miss, r4); |
1057 GenerateFastPropertyLoad(masm(), r1, reg, holder, index); | 1284 GenerateFastPropertyLoad(masm(), r1, reg, holder, index); |
1058 | 1285 |
1059 GenerateCallFunction(masm(), object, arguments(), &miss); | 1286 GenerateCallFunction(masm(), object, arguments(), &miss); |
1060 | 1287 |
1061 // Handle call cache miss. | 1288 // Handle call cache miss. |
1062 __ bind(&miss); | 1289 __ bind(&miss); |
1063 GenerateMissBranch(); | 1290 GenerateMissBranch(); |
1064 | 1291 |
1065 // Return the generated code. | 1292 // Return the generated code. |
1066 return GetCode(FIELD, name); | 1293 return GetCode(FIELD, name); |
(...skipping 24 matching lines...) Expand all Loading... |
1091 | 1318 |
1092 // Get the receiver from the stack | 1319 // Get the receiver from the stack |
1093 const int argc = arguments().immediate(); | 1320 const int argc = arguments().immediate(); |
1094 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | 1321 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
1095 | 1322 |
1096 // Check that the receiver isn't a smi. | 1323 // Check that the receiver isn't a smi. |
1097 __ tst(r1, Operand(kSmiTagMask)); | 1324 __ tst(r1, Operand(kSmiTagMask)); |
1098 __ b(eq, &miss); | 1325 __ b(eq, &miss); |
1099 | 1326 |
1100 // Check that the maps haven't changed. | 1327 // Check that the maps haven't changed. |
1101 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss); | 1328 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss, r4); |
1102 | 1329 |
1103 if (object->IsGlobalObject()) { | 1330 if (object->IsGlobalObject()) { |
1104 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | 1331 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); |
1105 __ str(r3, MemOperand(sp, argc * kPointerSize)); | 1332 __ str(r3, MemOperand(sp, argc * kPointerSize)); |
1106 } | 1333 } |
1107 | 1334 |
1108 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush), | 1335 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPush), |
1109 argc + 1, | 1336 argc + 1, |
1110 1); | 1337 1); |
1111 | 1338 |
(...skipping 30 matching lines...) Expand all Loading... |
1142 | 1369 |
1143 // Get the receiver from the stack | 1370 // Get the receiver from the stack |
1144 const int argc = arguments().immediate(); | 1371 const int argc = arguments().immediate(); |
1145 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | 1372 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
1146 | 1373 |
1147 // Check that the receiver isn't a smi. | 1374 // Check that the receiver isn't a smi. |
1148 __ tst(r1, Operand(kSmiTagMask)); | 1375 __ tst(r1, Operand(kSmiTagMask)); |
1149 __ b(eq, &miss); | 1376 __ b(eq, &miss); |
1150 | 1377 |
1151 // Check that the maps haven't changed. | 1378 // Check that the maps haven't changed. |
1152 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss); | 1379 CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss, r4); |
1153 | 1380 |
1154 if (object->IsGlobalObject()) { | 1381 if (object->IsGlobalObject()) { |
1155 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | 1382 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); |
1156 __ str(r3, MemOperand(sp, argc * kPointerSize)); | 1383 __ str(r3, MemOperand(sp, argc * kPointerSize)); |
1157 } | 1384 } |
1158 | 1385 |
1159 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop), | 1386 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop), |
1160 argc + 1, | 1387 argc + 1, |
1161 1); | 1388 1); |
1162 | 1389 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1240 JSObject::cast(object), holder); | 1467 JSObject::cast(object), holder); |
1241 } | 1468 } |
1242 | 1469 |
1243 if (depth != kInvalidProtoDepth) { | 1470 if (depth != kInvalidProtoDepth) { |
1244 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3); | 1471 __ IncrementCounter(&Counters::call_const_fast_api, 1, r0, r3); |
1245 ReserveSpaceForFastApiCall(masm(), r0); | 1472 ReserveSpaceForFastApiCall(masm(), r0); |
1246 } | 1473 } |
1247 | 1474 |
1248 // Check that the maps haven't changed. | 1475 // Check that the maps haven't changed. |
1249 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, name, | 1476 CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, name, |
1250 depth, &miss); | 1477 depth, &miss, r4); |
1251 | 1478 |
1252 // Patch the receiver on the stack with the global proxy if | 1479 // Patch the receiver on the stack with the global proxy if |
1253 // necessary. | 1480 // necessary. |
1254 if (object->IsGlobalObject()) { | 1481 if (object->IsGlobalObject()) { |
1255 ASSERT(depth == kInvalidProtoDepth); | 1482 ASSERT(depth == kInvalidProtoDepth); |
1256 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | 1483 __ ldr(r3, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); |
1257 __ str(r3, MemOperand(sp, argc * kPointerSize)); | 1484 __ str(r3, MemOperand(sp, argc * kPointerSize)); |
1258 } | 1485 } |
1259 break; | 1486 break; |
1260 | 1487 |
1261 case STRING_CHECK: | 1488 case STRING_CHECK: |
1262 if (!function->IsBuiltin()) { | 1489 if (!function->IsBuiltin()) { |
1263 // Calling non-builtins with a value as receiver requires boxing. | 1490 // Calling non-builtins with a value as receiver requires boxing. |
1264 __ jmp(&miss); | 1491 __ jmp(&miss); |
1265 } else { | 1492 } else { |
1266 // Check that the object is a two-byte string or a symbol. | 1493 // Check that the object is a two-byte string or a symbol. |
1267 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); | 1494 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); |
1268 __ b(hs, &miss); | 1495 __ b(hs, &miss); |
1269 // Check that the maps starting from the prototype haven't changed. | 1496 // Check that the maps starting from the prototype haven't changed. |
1270 GenerateDirectLoadGlobalFunctionPrototype( | 1497 GenerateDirectLoadGlobalFunctionPrototype( |
1271 masm(), Context::STRING_FUNCTION_INDEX, r0); | 1498 masm(), Context::STRING_FUNCTION_INDEX, r0); |
1272 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, | 1499 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, |
1273 r1, name, &miss); | 1500 r1, name, &miss, r4); |
1274 } | 1501 } |
1275 break; | 1502 break; |
1276 | 1503 |
1277 case NUMBER_CHECK: { | 1504 case NUMBER_CHECK: { |
1278 if (!function->IsBuiltin()) { | 1505 if (!function->IsBuiltin()) { |
1279 // Calling non-builtins with a value as receiver requires boxing. | 1506 // Calling non-builtins with a value as receiver requires boxing. |
1280 __ jmp(&miss); | 1507 __ jmp(&miss); |
1281 } else { | 1508 } else { |
1282 Label fast; | 1509 Label fast; |
1283 // Check that the object is a smi or a heap number. | 1510 // Check that the object is a smi or a heap number. |
1284 __ tst(r1, Operand(kSmiTagMask)); | 1511 __ tst(r1, Operand(kSmiTagMask)); |
1285 __ b(eq, &fast); | 1512 __ b(eq, &fast); |
1286 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE); | 1513 __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE); |
1287 __ b(ne, &miss); | 1514 __ b(ne, &miss); |
1288 __ bind(&fast); | 1515 __ bind(&fast); |
1289 // Check that the maps starting from the prototype haven't changed. | 1516 // Check that the maps starting from the prototype haven't changed. |
1290 GenerateDirectLoadGlobalFunctionPrototype( | 1517 GenerateDirectLoadGlobalFunctionPrototype( |
1291 masm(), Context::NUMBER_FUNCTION_INDEX, r0); | 1518 masm(), Context::NUMBER_FUNCTION_INDEX, r0); |
1292 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, | 1519 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, |
1293 r1, name, &miss); | 1520 r1, name, &miss, r4); |
1294 } | 1521 } |
1295 break; | 1522 break; |
1296 } | 1523 } |
1297 | 1524 |
1298 case BOOLEAN_CHECK: { | 1525 case BOOLEAN_CHECK: { |
1299 if (!function->IsBuiltin()) { | 1526 if (!function->IsBuiltin()) { |
1300 // Calling non-builtins with a value as receiver requires boxing. | 1527 // Calling non-builtins with a value as receiver requires boxing. |
1301 __ jmp(&miss); | 1528 __ jmp(&miss); |
1302 } else { | 1529 } else { |
1303 Label fast; | 1530 Label fast; |
1304 // Check that the object is a boolean. | 1531 // Check that the object is a boolean. |
1305 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 1532 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
1306 __ cmp(r1, ip); | 1533 __ cmp(r1, ip); |
1307 __ b(eq, &fast); | 1534 __ b(eq, &fast); |
1308 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 1535 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
1309 __ cmp(r1, ip); | 1536 __ cmp(r1, ip); |
1310 __ b(ne, &miss); | 1537 __ b(ne, &miss); |
1311 __ bind(&fast); | 1538 __ bind(&fast); |
1312 // Check that the maps starting from the prototype haven't changed. | 1539 // Check that the maps starting from the prototype haven't changed. |
1313 GenerateDirectLoadGlobalFunctionPrototype( | 1540 GenerateDirectLoadGlobalFunctionPrototype( |
1314 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0); | 1541 masm(), Context::BOOLEAN_FUNCTION_INDEX, r0); |
1315 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, | 1542 CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, |
1316 r1, name, &miss); | 1543 r1, name, &miss, r4); |
1317 } | 1544 } |
1318 break; | 1545 break; |
1319 } | 1546 } |
1320 | 1547 |
1321 default: | 1548 default: |
1322 UNREACHABLE(); | 1549 UNREACHABLE(); |
1323 } | 1550 } |
1324 | 1551 |
1325 if (depth != kInvalidProtoDepth) { | 1552 if (depth != kInvalidProtoDepth) { |
1326 GenerateFastApiCall(masm(), optimization, argc); | 1553 GenerateFastApiCall(masm(), optimization, argc); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1411 | 1638 |
1412 // If the object is the holder then we know that it's a global | 1639 // If the object is the holder then we know that it's a global |
1413 // object which can only happen for contextual calls. In this case, | 1640 // object which can only happen for contextual calls. In this case, |
1414 // the receiver cannot be a smi. | 1641 // the receiver cannot be a smi. |
1415 if (object != holder) { | 1642 if (object != holder) { |
1416 __ tst(r0, Operand(kSmiTagMask)); | 1643 __ tst(r0, Operand(kSmiTagMask)); |
1417 __ b(eq, &miss); | 1644 __ b(eq, &miss); |
1418 } | 1645 } |
1419 | 1646 |
1420 // Check that the maps haven't changed. | 1647 // Check that the maps haven't changed. |
1421 CheckPrototypes(object, r0, holder, r3, r1, name, &miss); | 1648 CheckPrototypes(object, r0, holder, r3, r1, name, &miss, r4); |
1422 | 1649 |
1423 // Get the value from the cell. | 1650 // Get the value from the cell. |
1424 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell))); | 1651 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell))); |
1425 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset)); | 1652 __ ldr(r1, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset)); |
1426 | 1653 |
1427 // Check that the cell contains the same function. | 1654 // Check that the cell contains the same function. |
1428 if (Heap::InNewSpace(function)) { | 1655 if (Heap::InNewSpace(function)) { |
1429 // We can't embed a pointer to a function in new space so we have | 1656 // We can't embed a pointer to a function in new space so we have |
1430 // to verify that the shared function info is unchanged. This has | 1657 // to verify that the shared function info is unchanged. This has |
1431 // the nice side effect that multiple closures based on the same | 1658 // the nice side effect that multiple closures based on the same |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1635 // -- r0 : receiver | 1862 // -- r0 : receiver |
1636 // -- lr : return address | 1863 // -- lr : return address |
1637 // ----------------------------------- | 1864 // ----------------------------------- |
1638 Label miss; | 1865 Label miss; |
1639 | 1866 |
1640 // Check that receiver is not a smi. | 1867 // Check that receiver is not a smi. |
1641 __ tst(r0, Operand(kSmiTagMask)); | 1868 __ tst(r0, Operand(kSmiTagMask)); |
1642 __ b(eq, &miss); | 1869 __ b(eq, &miss); |
1643 | 1870 |
1644 // Check the maps of the full prototype chain. | 1871 // Check the maps of the full prototype chain. |
1645 CheckPrototypes(object, r0, last, r3, r1, name, &miss); | 1872 CheckPrototypes(object, r0, last, r3, r1, name, &miss, r4); |
1646 | 1873 |
1647 // If the last object in the prototype chain is a global object, | 1874 // If the last object in the prototype chain is a global object, |
1648 // check that the global property cell is empty. | 1875 // check that the global property cell is empty. |
1649 if (last->IsGlobalObject()) { | 1876 if (last->IsGlobalObject()) { |
1650 Object* cell = GenerateCheckPropertyCell(masm(), | 1877 Object* cell = GenerateCheckPropertyCell(masm(), |
1651 GlobalObject::cast(last), | 1878 GlobalObject::cast(last), |
1652 name, | 1879 name, |
1653 r1, | 1880 r1, |
1654 &miss); | 1881 &miss); |
1655 if (cell->IsFailure()) return cell; | 1882 if (cell->IsFailure()) return cell; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1775 | 2002 |
1776 // If the object is the holder then we know that it's a global | 2003 // If the object is the holder then we know that it's a global |
1777 // object which can only happen for contextual calls. In this case, | 2004 // object which can only happen for contextual calls. In this case, |
1778 // the receiver cannot be a smi. | 2005 // the receiver cannot be a smi. |
1779 if (object != holder) { | 2006 if (object != holder) { |
1780 __ tst(r0, Operand(kSmiTagMask)); | 2007 __ tst(r0, Operand(kSmiTagMask)); |
1781 __ b(eq, &miss); | 2008 __ b(eq, &miss); |
1782 } | 2009 } |
1783 | 2010 |
1784 // Check that the map of the global has not changed. | 2011 // Check that the map of the global has not changed. |
1785 CheckPrototypes(object, r0, holder, r3, r4, name, &miss); | 2012 CheckPrototypes(object, r0, holder, r3, r4, name, &miss, r1); |
1786 | 2013 |
1787 // Get the value from the cell. | 2014 // Get the value from the cell. |
1788 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell))); | 2015 __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell))); |
1789 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset)); | 2016 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset)); |
1790 | 2017 |
1791 // Check for deleted property if property can actually be deleted. | 2018 // Check for deleted property if property can actually be deleted. |
1792 if (!is_dont_delete) { | 2019 if (!is_dont_delete) { |
1793 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2020 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
1794 __ cmp(r4, ip); | 2021 __ cmp(r4, ip); |
1795 __ b(eq, &miss); | 2022 __ b(eq, &miss); |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2149 // Return the generated code. | 2376 // Return the generated code. |
2150 return GetCode(); | 2377 return GetCode(); |
2151 } | 2378 } |
2152 | 2379 |
2153 | 2380 |
2154 #undef __ | 2381 #undef __ |
2155 | 2382 |
2156 } } // namespace v8::internal | 2383 } } // namespace v8::internal |
2157 | 2384 |
2158 #endif // V8_TARGET_ARCH_ARM | 2385 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |