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