| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1048 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1059 Handle<Code> stub = generic_stub(); | 1059 Handle<Code> stub = generic_stub(); |
| 1060 | 1060 |
| 1061 // Check for non-string values that can be converted into an | 1061 // Check for non-string values that can be converted into an |
| 1062 // internalized string directly or is representable as a smi. | 1062 // internalized string directly or is representable as a smi. |
| 1063 key = TryConvertKey(key, isolate()); | 1063 key = TryConvertKey(key, isolate()); |
| 1064 | 1064 |
| 1065 if (key->IsInternalizedString()) { | 1065 if (key->IsInternalizedString()) { |
| 1066 maybe_object = LoadIC::Load(object, Handle<String>::cast(key)); | 1066 maybe_object = LoadIC::Load(object, Handle<String>::cast(key)); |
| 1067 if (maybe_object->IsFailure()) return maybe_object; | 1067 if (maybe_object->IsFailure()) return maybe_object; |
| 1068 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) { | 1068 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) { |
| 1069 ASSERT(!object->IsAccessCheckNeeded()); | 1069 ASSERT(!object->IsJSGlobalProxy()); |
| 1070 if (object->IsString() && key->IsNumber()) { | 1070 if (object->IsString() && key->IsNumber()) { |
| 1071 if (state() == UNINITIALIZED) stub = string_stub(); | 1071 if (state() == UNINITIALIZED) stub = string_stub(); |
| 1072 } else if (object->IsJSObject()) { | 1072 } else if (object->IsJSObject()) { |
| 1073 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1073 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1074 if (receiver->elements()->map() == | 1074 if (receiver->elements()->map() == |
| 1075 isolate()->heap()->non_strict_arguments_elements_map()) { | 1075 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 1076 stub = non_strict_arguments_stub(); | 1076 stub = non_strict_arguments_stub(); |
| 1077 } else if (receiver->HasIndexedInterceptor()) { | 1077 } else if (receiver->HasIndexedInterceptor()) { |
| 1078 stub = indexed_interceptor_stub(); | 1078 stub = indexed_interceptor_stub(); |
| 1079 } else if (!key->ToSmi()->IsFailure() && | 1079 } else if (!key->ToSmi()->IsFailure() && |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1098 | 1098 |
| 1099 | 1099 |
| 1100 static bool LookupForWrite(Handle<JSObject> receiver, | 1100 static bool LookupForWrite(Handle<JSObject> receiver, |
| 1101 Handle<String> name, | 1101 Handle<String> name, |
| 1102 Handle<Object> value, | 1102 Handle<Object> value, |
| 1103 LookupResult* lookup, | 1103 LookupResult* lookup, |
| 1104 IC* ic) { | 1104 IC* ic) { |
| 1105 Handle<JSObject> holder = receiver; | 1105 Handle<JSObject> holder = receiver; |
| 1106 receiver->Lookup(*name, lookup); | 1106 receiver->Lookup(*name, lookup); |
| 1107 if (lookup->IsFound()) { | 1107 if (lookup->IsFound()) { |
| 1108 if (lookup->IsInterceptor() && !HasInterceptorSetter(lookup->holder())) { | 1108 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; |
| 1109 receiver->LocalLookupRealNamedProperty(*name, lookup); | 1109 |
| 1110 if (!lookup->IsFound()) return false; | 1110 if (lookup->holder() == *receiver) { |
| 1111 if (lookup->IsInterceptor() && !HasInterceptorSetter(*receiver)) { |
| 1112 receiver->LocalLookupRealNamedProperty(*name, lookup); |
| 1113 return lookup->IsFound() && |
| 1114 !lookup->IsReadOnly() && |
| 1115 lookup->CanHoldValue(value) && |
| 1116 lookup->IsCacheable(); |
| 1117 } |
| 1118 return lookup->CanHoldValue(value); |
| 1111 } | 1119 } |
| 1112 | 1120 |
| 1113 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; | |
| 1114 if (lookup->holder() == *receiver) return lookup->CanHoldValue(value); | |
| 1115 if (lookup->IsPropertyCallbacks()) return true; | 1121 if (lookup->IsPropertyCallbacks()) return true; |
| 1116 // JSGlobalProxy either stores on the global object in the prototype, or | 1122 // JSGlobalProxy always goes via the runtime, so it's safe to cache. |
| 1117 // goes into the runtime if access checks are needed, so this is always | |
| 1118 // safe. | |
| 1119 if (receiver->IsJSGlobalProxy()) return true; | 1123 if (receiver->IsJSGlobalProxy()) return true; |
| 1120 // Currently normal holders in the prototype chain are not supported. They | 1124 // Currently normal holders in the prototype chain are not supported. They |
| 1121 // would require a runtime positive lookup and verification that the details | 1125 // would require a runtime positive lookup and verification that the details |
| 1122 // have not changed. | 1126 // have not changed. |
| 1123 if (lookup->IsInterceptor() || lookup->IsNormal()) return false; | 1127 if (lookup->IsInterceptor() || lookup->IsNormal()) return false; |
| 1124 holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); | 1128 holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); |
| 1125 } | 1129 } |
| 1126 | 1130 |
| 1127 // While normally LookupTransition gets passed the receiver, in this case we | 1131 // While normally LookupTransition gets passed the receiver, in this case we |
| 1128 // pass the holder of the property that we overwrite. This keeps the holder in | 1132 // pass the holder of the property that we overwrite. This keeps the holder in |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1294 PatchCache(CurrentTypeOf(receiver, isolate()), name, code); | 1298 PatchCache(CurrentTypeOf(receiver, isolate()), name, code); |
| 1295 TRACE_IC("StoreIC", name); | 1299 TRACE_IC("StoreIC", name); |
| 1296 } | 1300 } |
| 1297 | 1301 |
| 1298 | 1302 |
| 1299 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, | 1303 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
| 1300 Handle<Object> object, | 1304 Handle<Object> object, |
| 1301 Handle<String> name, | 1305 Handle<String> name, |
| 1302 Handle<Object> value, | 1306 Handle<Object> value, |
| 1303 InlineCacheHolderFlag cache_holder) { | 1307 InlineCacheHolderFlag cache_holder) { |
| 1304 if (object->IsAccessCheckNeeded()) return slow_stub(); | 1308 if (object->IsJSGlobalProxy()) return slow_stub(); |
| 1305 ASSERT(cache_holder == OWN_MAP); | 1309 ASSERT(cache_holder == OWN_MAP); |
| 1306 // This is currently guaranteed by checks in StoreIC::Store. | 1310 // This is currently guaranteed by checks in StoreIC::Store. |
| 1307 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1311 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1308 | 1312 |
| 1309 Handle<JSObject> holder(lookup->holder()); | 1313 Handle<JSObject> holder(lookup->holder()); |
| 1310 // Handlers do not use strict mode. | 1314 // Handlers do not use strict mode. |
| 1311 StoreStubCompiler compiler(isolate(), kNonStrictMode, kind()); | 1315 StoreStubCompiler compiler(isolate(), kNonStrictMode, kind()); |
| 1312 switch (lookup->type()) { | 1316 switch (lookup->type()) { |
| 1313 case FIELD: | 1317 case FIELD: |
| 1314 return compiler.CompileStoreField(receiver, lookup, name); | 1318 return compiler.CompileStoreField(receiver, lookup, name); |
| 1315 case TRANSITION: { | 1319 case TRANSITION: { |
| 1316 // Explicitly pass in the receiver map since LookupForWrite may have | 1320 // Explicitly pass in the receiver map since LookupForWrite may have |
| 1317 // stored something else than the receiver in the holder. | 1321 // stored something else than the receiver in the holder. |
| 1318 Handle<Map> transition(lookup->GetTransitionTarget()); | 1322 Handle<Map> transition(lookup->GetTransitionTarget()); |
| 1319 PropertyDetails details = transition->GetLastDescriptorDetails(); | 1323 PropertyDetails details = transition->GetLastDescriptorDetails(); |
| 1320 | 1324 |
| 1321 if (details.type() == CALLBACKS || details.attributes() != NONE) break; | 1325 if (details.type() == CALLBACKS || details.attributes() != NONE) break; |
| 1322 | 1326 |
| 1323 return compiler.CompileStoreTransition( | 1327 return compiler.CompileStoreTransition( |
| 1324 receiver, lookup, transition, name); | 1328 receiver, lookup, transition, name); |
| 1325 } | 1329 } |
| 1326 case NORMAL: | 1330 case NORMAL: |
| 1327 if (kind() == Code::KEYED_STORE_IC) break; | 1331 if (kind() == Code::KEYED_STORE_IC) break; |
| 1328 if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) { | 1332 if (receiver->IsGlobalObject()) { |
| 1329 // The stub generated for the global object picks the value directly | 1333 // The stub generated for the global object picks the value directly |
| 1330 // from the property cell. So the property must be directly on the | 1334 // from the property cell. So the property must be directly on the |
| 1331 // global object. | 1335 // global object. |
| 1332 Handle<GlobalObject> global = receiver->IsJSGlobalProxy() | 1336 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1333 ? handle(GlobalObject::cast(receiver->GetPrototype())) | |
| 1334 : Handle<GlobalObject>::cast(receiver); | |
| 1335 Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate()); | 1337 Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate()); |
| 1336 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); | 1338 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); |
| 1337 StoreGlobalStub stub( | 1339 StoreGlobalStub stub(union_type->IsConstant()); |
| 1338 union_type->IsConstant(), receiver->IsJSGlobalProxy()); | 1340 |
| 1339 Handle<Code> code = stub.GetCodeCopyFromTemplate( | 1341 Handle<Code> code = stub.GetCodeCopyFromTemplate( |
| 1340 isolate(), *global, *cell); | 1342 isolate(), receiver->map(), *cell); |
| 1341 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | 1343 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
| 1342 HeapObject::UpdateMapCodeCache(receiver, name, code); | 1344 HeapObject::UpdateMapCodeCache(receiver, name, code); |
| 1343 return code; | 1345 return code; |
| 1344 } | 1346 } |
| 1345 ASSERT(holder.is_identical_to(receiver)); | 1347 ASSERT(holder.is_identical_to(receiver)); |
| 1346 return isolate()->builtins()->StoreIC_Normal(); | 1348 return isolate()->builtins()->StoreIC_Normal(); |
| 1347 case CALLBACKS: { | 1349 case CALLBACKS: { |
| 1348 if (kind() == Code::KEYED_STORE_IC) break; | 1350 if (kind() == Code::KEYED_STORE_IC) break; |
| 1349 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1351 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1350 if (callback->IsExecutableAccessorInfo()) { | 1352 if (callback->IsExecutableAccessorInfo()) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1371 receiver, holder, name, Handle<JSFunction>::cast(setter)); | 1373 receiver, holder, name, Handle<JSFunction>::cast(setter)); |
| 1372 } | 1374 } |
| 1373 // TODO(dcarney): Handle correctly. | 1375 // TODO(dcarney): Handle correctly. |
| 1374 if (callback->IsDeclaredAccessorInfo()) break; | 1376 if (callback->IsDeclaredAccessorInfo()) break; |
| 1375 ASSERT(callback->IsForeign()); | 1377 ASSERT(callback->IsForeign()); |
| 1376 // No IC support for old-style native accessors. | 1378 // No IC support for old-style native accessors. |
| 1377 break; | 1379 break; |
| 1378 } | 1380 } |
| 1379 case INTERCEPTOR: | 1381 case INTERCEPTOR: |
| 1380 if (kind() == Code::KEYED_STORE_IC) break; | 1382 if (kind() == Code::KEYED_STORE_IC) break; |
| 1381 ASSERT(HasInterceptorSetter(*holder)); | 1383 ASSERT(HasInterceptorSetter(*receiver)); |
| 1382 return compiler.CompileStoreInterceptor(receiver, name); | 1384 return compiler.CompileStoreInterceptor(receiver, name); |
| 1383 case CONSTANT: | 1385 case CONSTANT: |
| 1384 break; | 1386 break; |
| 1385 case NONEXISTENT: | 1387 case NONEXISTENT: |
| 1386 case HANDLER: | 1388 case HANDLER: |
| 1387 UNREACHABLE(); | 1389 UNREACHABLE(); |
| 1388 break; | 1390 break; |
| 1389 } | 1391 } |
| 1390 return slow_stub(); | 1392 return slow_stub(); |
| 1391 } | 1393 } |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1658 JSObject::cast(*object)->map()->is_observed()); | 1660 JSObject::cast(*object)->map()->is_observed()); |
| 1659 if (use_ic && !object->IsSmi()) { | 1661 if (use_ic && !object->IsSmi()) { |
| 1660 // Don't use ICs for maps of the objects in Array's prototype chain. We | 1662 // Don't use ICs for maps of the objects in Array's prototype chain. We |
| 1661 // expect to be able to trap element sets to objects with those maps in | 1663 // expect to be able to trap element sets to objects with those maps in |
| 1662 // the runtime to enable optimization of element hole access. | 1664 // the runtime to enable optimization of element hole access. |
| 1663 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); | 1665 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); |
| 1664 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false; | 1666 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false; |
| 1665 } | 1667 } |
| 1666 | 1668 |
| 1667 if (use_ic) { | 1669 if (use_ic) { |
| 1668 ASSERT(!object->IsAccessCheckNeeded()); | 1670 ASSERT(!object->IsJSGlobalProxy()); |
| 1669 | 1671 |
| 1670 if (object->IsJSObject()) { | 1672 if (object->IsJSObject()) { |
| 1671 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1673 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1672 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure(); | 1674 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure(); |
| 1673 if (receiver->elements()->map() == | 1675 if (receiver->elements()->map() == |
| 1674 isolate()->heap()->non_strict_arguments_elements_map()) { | 1676 isolate()->heap()->non_strict_arguments_elements_map()) { |
| 1675 stub = non_strict_arguments_stub(); | 1677 stub = non_strict_arguments_stub(); |
| 1676 } else if (key_is_smi_like && | 1678 } else if (key_is_smi_like && |
| 1677 !(target().is_identical_to(non_strict_arguments_stub()))) { | 1679 !(target().is_identical_to(non_strict_arguments_stub()))) { |
| 1678 // We should go generic if receiver isn't a dictionary, but our | 1680 // We should go generic if receiver isn't a dictionary, but our |
| (...skipping 1117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2796 #undef ADDR | 2798 #undef ADDR |
| 2797 }; | 2799 }; |
| 2798 | 2800 |
| 2799 | 2801 |
| 2800 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2802 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2801 return IC_utilities[id]; | 2803 return IC_utilities[id]; |
| 2802 } | 2804 } |
| 2803 | 2805 |
| 2804 | 2806 |
| 2805 } } // namespace v8::internal | 2807 } } // namespace v8::internal |
| OLD | NEW |