| 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 1149 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1160     if (lookup->IsInterceptor() || lookup->IsNormal()) return false; | 1160     if (lookup->IsInterceptor() || lookup->IsNormal()) return false; | 
| 1161     holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); | 1161     holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); | 
| 1162   } | 1162   } | 
| 1163 | 1163 | 
| 1164   // While normally LookupTransition gets passed the receiver, in this case we | 1164   // While normally LookupTransition gets passed the receiver, in this case we | 
| 1165   // pass the holder of the property that we overwrite. This keeps the holder in | 1165   // pass the holder of the property that we overwrite. This keeps the holder in | 
| 1166   // the LookupResult intact so we can later use it to generate a prototype | 1166   // the LookupResult intact so we can later use it to generate a prototype | 
| 1167   // chain check. This avoids a double lookup, but requires us to pass in the | 1167   // chain check. This avoids a double lookup, but requires us to pass in the | 
| 1168   // receiver when trying to fetch extra information from the transition. | 1168   // receiver when trying to fetch extra information from the transition. | 
| 1169   receiver->map()->LookupTransition(*holder, *name, lookup); | 1169   receiver->map()->LookupTransition(*holder, *name, lookup); | 
| 1170   if (!lookup->IsTransition()) return false; | 1170   if (!lookup->IsTransition() || lookup->IsReadOnly()) return false; | 
| 1171   PropertyDetails target_details = lookup->GetTransitionDetails(); |  | 
| 1172   if (target_details.IsReadOnly()) return false; |  | 
| 1173 | 1171 | 
| 1174   // If the value that's being stored does not fit in the field that the | 1172   // If the value that's being stored does not fit in the field that the | 
| 1175   // instance would transition to, create a new transition that fits the value. | 1173   // instance would transition to, create a new transition that fits the value. | 
| 1176   // This has to be done before generating the IC, since that IC will embed the | 1174   // This has to be done before generating the IC, since that IC will embed the | 
| 1177   // transition target. | 1175   // transition target. | 
| 1178   // Ensure the instance and its map were migrated before trying to update the | 1176   // Ensure the instance and its map were migrated before trying to update the | 
| 1179   // transition target. | 1177   // transition target. | 
| 1180   ASSERT(!receiver->map()->is_deprecated()); | 1178   ASSERT(!receiver->map()->is_deprecated()); | 
| 1181   if (!value->FitsRepresentation(target_details.representation())) { | 1179   if (!lookup->CanHoldValue(value)) { | 
| 1182     Handle<Map> target(lookup->GetTransitionTarget()); | 1180     Handle<Map> target(lookup->GetTransitionTarget()); | 
| 1183     Map::GeneralizeRepresentation( | 1181     Map::GeneralizeRepresentation( | 
| 1184         target, target->LastAdded(), | 1182         target, target->LastAdded(), | 
| 1185         value->OptimalRepresentation(), FORCE_FIELD); | 1183         value->OptimalRepresentation(), FORCE_FIELD); | 
| 1186     // Lookup the transition again since the transition tree may have changed | 1184     // Lookup the transition again since the transition tree may have changed | 
| 1187     // entirely by the migration above. | 1185     // entirely by the migration above. | 
| 1188     receiver->map()->LookupTransition(*holder, *name, lookup); | 1186     receiver->map()->LookupTransition(*holder, *name, lookup); | 
| 1189     if (!lookup->IsTransition()) return false; | 1187     if (!lookup->IsTransition()) return false; | 
| 1190     return ic->TryMarkMonomorphicPrototypeFailure(name); | 1188     return ic->TryMarkMonomorphicPrototypeFailure(name); | 
| 1191   } | 1189   } | 
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1320                                      Handle<Object> value, | 1318                                      Handle<Object> value, | 
| 1321                                      InlineCacheHolderFlag cache_holder) { | 1319                                      InlineCacheHolderFlag cache_holder) { | 
| 1322   if (object->IsAccessCheckNeeded()) return slow_stub(); | 1320   if (object->IsAccessCheckNeeded()) return slow_stub(); | 
| 1323   ASSERT(cache_holder == OWN_MAP); | 1321   ASSERT(cache_holder == OWN_MAP); | 
| 1324   // This is currently guaranteed by checks in StoreIC::Store. | 1322   // This is currently guaranteed by checks in StoreIC::Store. | 
| 1325   Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1323   Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 
| 1326 | 1324 | 
| 1327   Handle<JSObject> holder(lookup->holder()); | 1325   Handle<JSObject> holder(lookup->holder()); | 
| 1328   // Handlers do not use strict mode. | 1326   // Handlers do not use strict mode. | 
| 1329   StoreStubCompiler compiler(isolate(), SLOPPY, kind()); | 1327   StoreStubCompiler compiler(isolate(), SLOPPY, kind()); | 
| 1330   switch (lookup->type()) { | 1328   if (lookup->IsTransition()) { | 
| 1331     case FIELD: | 1329     // Explicitly pass in the receiver map since LookupForWrite may have | 
| 1332       return compiler.CompileStoreField(receiver, lookup, name); | 1330     // stored something else than the receiver in the holder. | 
| 1333     case TRANSITION: { | 1331     Handle<Map> transition(lookup->GetTransitionTarget()); | 
| 1334       // Explicitly pass in the receiver map since LookupForWrite may have | 1332     PropertyDetails details = lookup->GetPropertyDetails(); | 
| 1335       // stored something else than the receiver in the holder. |  | 
| 1336       Handle<Map> transition(lookup->GetTransitionTarget()); |  | 
| 1337       PropertyDetails details = transition->GetLastDescriptorDetails(); |  | 
| 1338 | 1333 | 
| 1339       if (details.type() == CALLBACKS || details.attributes() != NONE) break; | 1334     if (details.type() != CALLBACKS && details.attributes() == NONE) { | 
| 1340 |  | 
| 1341       return compiler.CompileStoreTransition( | 1335       return compiler.CompileStoreTransition( | 
| 1342           receiver, lookup, transition, name); | 1336           receiver, lookup, transition, name); | 
| 1343     } | 1337     } | 
| 1344     case NORMAL: | 1338   } else { | 
| 1345       if (kind() == Code::KEYED_STORE_IC) break; | 1339     switch (lookup->type()) { | 
| 1346       if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) { | 1340       case FIELD: | 
| 1347         // The stub generated for the global object picks the value directly | 1341         return compiler.CompileStoreField(receiver, lookup, name); | 
| 1348         // from the property cell. So the property must be directly on the | 1342       case NORMAL: | 
| 1349         // global object. | 1343         if (kind() == Code::KEYED_STORE_IC) break; | 
| 1350         Handle<GlobalObject> global = receiver->IsJSGlobalProxy() | 1344         if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) { | 
| 1351             ? handle(GlobalObject::cast(receiver->GetPrototype())) | 1345           // The stub generated for the global object picks the value directly | 
| 1352             : Handle<GlobalObject>::cast(receiver); | 1346           // from the property cell. So the property must be directly on the | 
| 1353         Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate()); | 1347           // global object. | 
| 1354         Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); | 1348           Handle<GlobalObject> global = receiver->IsJSGlobalProxy() | 
| 1355         StoreGlobalStub stub( | 1349               ? handle(GlobalObject::cast(receiver->GetPrototype())) | 
| 1356             union_type->IsConstant(), receiver->IsJSGlobalProxy()); | 1350               : Handle<GlobalObject>::cast(receiver); | 
| 1357         Handle<Code> code = stub.GetCodeCopyFromTemplate( | 1351           Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate()); | 
| 1358             isolate(), global, cell); | 1352           Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); | 
| 1359         // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | 1353           StoreGlobalStub stub( | 
| 1360         HeapObject::UpdateMapCodeCache(receiver, name, code); | 1354               union_type->IsConstant(), receiver->IsJSGlobalProxy()); | 
| 1361         return code; | 1355           Handle<Code> code = stub.GetCodeCopyFromTemplate( | 
|  | 1356               isolate(), global, cell); | 
|  | 1357           // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | 
|  | 1358           HeapObject::UpdateMapCodeCache(receiver, name, code); | 
|  | 1359           return code; | 
|  | 1360         } | 
|  | 1361         ASSERT(holder.is_identical_to(receiver)); | 
|  | 1362         return isolate()->builtins()->StoreIC_Normal(); | 
|  | 1363       case CALLBACKS: { | 
|  | 1364         Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 
|  | 1365         if (callback->IsExecutableAccessorInfo()) { | 
|  | 1366           Handle<ExecutableAccessorInfo> info = | 
|  | 1367               Handle<ExecutableAccessorInfo>::cast(callback); | 
|  | 1368           if (v8::ToCData<Address>(info->setter()) == 0) break; | 
|  | 1369           if (!holder->HasFastProperties()) break; | 
|  | 1370           if (!info->IsCompatibleReceiver(*receiver)) break; | 
|  | 1371           return compiler.CompileStoreCallback(receiver, holder, name, info); | 
|  | 1372         } else if (callback->IsAccessorPair()) { | 
|  | 1373           Handle<Object> setter( | 
|  | 1374               Handle<AccessorPair>::cast(callback)->setter(), isolate()); | 
|  | 1375           if (!setter->IsJSFunction()) break; | 
|  | 1376           if (holder->IsGlobalObject()) break; | 
|  | 1377           if (!holder->HasFastProperties()) break; | 
|  | 1378           Handle<JSFunction> function = Handle<JSFunction>::cast(setter); | 
|  | 1379           CallOptimization call_optimization(function); | 
|  | 1380           if (call_optimization.is_simple_api_call() && | 
|  | 1381               call_optimization.IsCompatibleReceiver(receiver, holder)) { | 
|  | 1382             return compiler.CompileStoreCallback( | 
|  | 1383                 receiver, holder, name, call_optimization); | 
|  | 1384           } | 
|  | 1385           return compiler.CompileStoreViaSetter( | 
|  | 1386               receiver, holder, name, Handle<JSFunction>::cast(setter)); | 
|  | 1387         } | 
|  | 1388         // TODO(dcarney): Handle correctly. | 
|  | 1389         if (callback->IsDeclaredAccessorInfo()) break; | 
|  | 1390         ASSERT(callback->IsForeign()); | 
|  | 1391 | 
|  | 1392         // Use specialized code for setting the length of arrays with fast | 
|  | 1393         // properties. Slow properties might indicate redefinition of the length | 
|  | 1394         // property. | 
|  | 1395         if (receiver->IsJSArray() && | 
|  | 1396             name->Equals(isolate()->heap()->length_string()) && | 
|  | 1397             Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && | 
|  | 1398             receiver->HasFastProperties()) { | 
|  | 1399           return compiler.CompileStoreArrayLength(receiver, lookup, name); | 
|  | 1400         } | 
|  | 1401 | 
|  | 1402         // No IC support for old-style native accessors. | 
|  | 1403         break; | 
| 1362       } | 1404       } | 
| 1363       ASSERT(holder.is_identical_to(receiver)); | 1405       case INTERCEPTOR: | 
| 1364       return isolate()->builtins()->StoreIC_Normal(); | 1406         if (kind() == Code::KEYED_STORE_IC) break; | 
| 1365     case CALLBACKS: { | 1407         ASSERT(HasInterceptorSetter(*holder)); | 
| 1366       Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1408         return compiler.CompileStoreInterceptor(receiver, name); | 
| 1367       if (callback->IsExecutableAccessorInfo()) { | 1409       case CONSTANT: | 
| 1368         Handle<ExecutableAccessorInfo> info = | 1410         break; | 
| 1369             Handle<ExecutableAccessorInfo>::cast(callback); | 1411       case NONEXISTENT: | 
| 1370         if (v8::ToCData<Address>(info->setter()) == 0) break; | 1412       case HANDLER: | 
| 1371         if (!holder->HasFastProperties()) break; | 1413         UNREACHABLE(); | 
| 1372         if (!info->IsCompatibleReceiver(*receiver)) break; | 1414         break; | 
| 1373         return compiler.CompileStoreCallback(receiver, holder, name, info); |  | 
| 1374       } else if (callback->IsAccessorPair()) { |  | 
| 1375         Handle<Object> setter( |  | 
| 1376             Handle<AccessorPair>::cast(callback)->setter(), isolate()); |  | 
| 1377         if (!setter->IsJSFunction()) break; |  | 
| 1378         if (holder->IsGlobalObject()) break; |  | 
| 1379         if (!holder->HasFastProperties()) break; |  | 
| 1380         Handle<JSFunction> function = Handle<JSFunction>::cast(setter); |  | 
| 1381         CallOptimization call_optimization(function); |  | 
| 1382         if (call_optimization.is_simple_api_call() && |  | 
| 1383             call_optimization.IsCompatibleReceiver(receiver, holder)) { |  | 
| 1384           return compiler.CompileStoreCallback( |  | 
| 1385               receiver, holder, name, call_optimization); |  | 
| 1386         } |  | 
| 1387         return compiler.CompileStoreViaSetter( |  | 
| 1388             receiver, holder, name, Handle<JSFunction>::cast(setter)); |  | 
| 1389       } |  | 
| 1390       // TODO(dcarney): Handle correctly. |  | 
| 1391       if (callback->IsDeclaredAccessorInfo()) break; |  | 
| 1392       ASSERT(callback->IsForeign()); |  | 
| 1393 |  | 
| 1394       // Use specialized code for setting the length of arrays with fast |  | 
| 1395       // properties. Slow properties might indicate redefinition of the length |  | 
| 1396       // property. |  | 
| 1397       if (receiver->IsJSArray() && |  | 
| 1398           name->Equals(isolate()->heap()->length_string()) && |  | 
| 1399           Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && |  | 
| 1400           receiver->HasFastProperties()) { |  | 
| 1401         return compiler.CompileStoreArrayLength(receiver, lookup, name); |  | 
| 1402       } |  | 
| 1403 |  | 
| 1404       // No IC support for old-style native accessors. |  | 
| 1405       break; |  | 
| 1406     } | 1415     } | 
| 1407     case INTERCEPTOR: |  | 
| 1408       if (kind() == Code::KEYED_STORE_IC) break; |  | 
| 1409       ASSERT(HasInterceptorSetter(*holder)); |  | 
| 1410       return compiler.CompileStoreInterceptor(receiver, name); |  | 
| 1411     case CONSTANT: |  | 
| 1412       break; |  | 
| 1413     case NONEXISTENT: |  | 
| 1414     case HANDLER: |  | 
| 1415       UNREACHABLE(); |  | 
| 1416       break; |  | 
| 1417   } | 1416   } | 
| 1418   return slow_stub(); | 1417   return slow_stub(); | 
| 1419 } | 1418 } | 
| 1420 | 1419 | 
| 1421 | 1420 | 
| 1422 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, | 1421 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, | 
| 1423                                             KeyedAccessStoreMode store_mode) { | 1422                                             KeyedAccessStoreMode store_mode) { | 
| 1424   // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1423   // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 
| 1425   // via megamorphic stubs, since they don't have a map in their relocation info | 1424   // via megamorphic stubs, since they don't have a map in their relocation info | 
| 1426   // and so the stubs can't be harvested for the object needed for a map check. | 1425   // and so the stubs can't be harvested for the object needed for a map check. | 
| (...skipping 1406 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2833 #undef ADDR | 2832 #undef ADDR | 
| 2834 }; | 2833 }; | 
| 2835 | 2834 | 
| 2836 | 2835 | 
| 2837 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2836 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 
| 2838   return IC_utilities[id]; | 2837   return IC_utilities[id]; | 
| 2839 } | 2838 } | 
| 2840 | 2839 | 
| 2841 | 2840 | 
| 2842 } }  // namespace v8::internal | 2841 } }  // namespace v8::internal | 
| OLD | NEW | 
|---|