| 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 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 // Reset the map check of the inlined inobject property store (if | 335 // Reset the map check of the inlined inobject property store (if |
| 336 // present) to guarantee failure by holding an invalid map (the null | 336 // present) to guarantee failure by holding an invalid map (the null |
| 337 // value). The offset can be patched to anything. | 337 // value). The offset can be patched to anything. |
| 338 PatchInlinedStore(address, Heap::null_value(), 0); | 338 PatchInlinedStore(address, Heap::null_value(), 0); |
| 339 } | 339 } |
| 340 | 340 |
| 341 | 341 |
| 342 void StoreIC::Clear(Address address, Code* target) { | 342 void StoreIC::Clear(Address address, Code* target) { |
| 343 if (target->ic_state() == UNINITIALIZED) return; | 343 if (target->ic_state() == UNINITIALIZED) return; |
| 344 ClearInlinedVersion(address); | 344 ClearInlinedVersion(address); |
| 345 SetTargetAtAddress(address, initialize_stub()); | 345 SetTargetAtAddress(address, |
| 346 target->extra_ic_state() == kStoreICStrict |
| 347 ? initialize_stub_strict() |
| 348 : initialize_stub()); |
| 346 } | 349 } |
| 347 | 350 |
| 348 | 351 |
| 349 void KeyedStoreIC::ClearInlinedVersion(Address address) { | 352 void KeyedStoreIC::ClearInlinedVersion(Address address) { |
| 350 // Insert null as the elements map to check for. This will make | 353 // Insert null as the elements map to check for. This will make |
| 351 // sure that the elements fast-case map check fails so that control | 354 // sure that the elements fast-case map check fails so that control |
| 352 // flows to the IC instead of the inlined version. | 355 // flows to the IC instead of the inlined version. |
| 353 PatchInlinedStore(address, Heap::null_value()); | 356 PatchInlinedStore(address, Heap::null_value()); |
| 354 } | 357 } |
| 355 | 358 |
| (...skipping 1005 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1361 object->LocalLookupRealNamedProperty(name, lookup); | 1364 object->LocalLookupRealNamedProperty(name, lookup); |
| 1362 return StoreICableLookup(lookup); | 1365 return StoreICableLookup(lookup); |
| 1363 } | 1366 } |
| 1364 } | 1367 } |
| 1365 | 1368 |
| 1366 return true; | 1369 return true; |
| 1367 } | 1370 } |
| 1368 | 1371 |
| 1369 | 1372 |
| 1370 MaybeObject* StoreIC::Store(State state, | 1373 MaybeObject* StoreIC::Store(State state, |
| 1374 Code::ExtraICState extra_ic_state, |
| 1371 Handle<Object> object, | 1375 Handle<Object> object, |
| 1372 Handle<String> name, | 1376 Handle<String> name, |
| 1373 Handle<Object> value) { | 1377 Handle<Object> value) { |
| 1374 // If the object is undefined or null it's illegal to try to set any | 1378 // If the object is undefined or null it's illegal to try to set any |
| 1375 // properties on it; throw a TypeError in that case. | 1379 // properties on it; throw a TypeError in that case. |
| 1376 if (object->IsUndefined() || object->IsNull()) { | 1380 if (object->IsUndefined() || object->IsNull()) { |
| 1377 return TypeError("non_object_property_store", object, name); | 1381 return TypeError("non_object_property_store", object, name); |
| 1378 } | 1382 } |
| 1379 | 1383 |
| 1380 // Ignore stores where the receiver is not a JSObject. | 1384 // Ignore stores where the receiver is not a JSObject. |
| 1381 if (!object->IsJSObject()) return *value; | 1385 if (!object->IsJSObject()) return *value; |
| 1382 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1386 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1383 | 1387 |
| 1384 // Check if the given name is an array index. | 1388 // Check if the given name is an array index. |
| 1385 uint32_t index; | 1389 uint32_t index; |
| 1386 if (name->AsArrayIndex(&index)) { | 1390 if (name->AsArrayIndex(&index)) { |
| 1387 HandleScope scope; | 1391 HandleScope scope; |
| 1388 Handle<Object> result = SetElement(receiver, index, value); | 1392 Handle<Object> result = SetElement(receiver, index, value); |
| 1389 if (result.is_null()) return Failure::Exception(); | 1393 if (result.is_null()) return Failure::Exception(); |
| 1390 return *value; | 1394 return *value; |
| 1391 } | 1395 } |
| 1392 | 1396 |
| 1393 // Use specialized code for setting the length of arrays. | 1397 // Use specialized code for setting the length of arrays. |
| 1394 if (receiver->IsJSArray() | 1398 if (receiver->IsJSArray() |
| 1395 && name->Equals(Heap::length_symbol()) | 1399 && name->Equals(Heap::length_symbol()) |
| 1396 && receiver->AllowsSetElementsLength()) { | 1400 && receiver->AllowsSetElementsLength()) { |
| 1397 #ifdef DEBUG | 1401 #ifdef DEBUG |
| 1398 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); | 1402 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); |
| 1399 #endif | 1403 #endif |
| 1400 Code* target = Builtins::builtin(Builtins::StoreIC_ArrayLength); | 1404 Builtins::Name target = (extra_ic_state == kStoreICStrict) |
| 1401 set_target(target); | 1405 ? Builtins::StoreIC_ArrayLength_Strict |
| 1406 : Builtins::StoreIC_ArrayLength; |
| 1407 set_target(Builtins::builtin(target)); |
| 1402 return receiver->SetProperty(*name, *value, NONE); | 1408 return receiver->SetProperty(*name, *value, NONE); |
| 1403 } | 1409 } |
| 1404 | 1410 |
| 1405 // Lookup the property locally in the receiver. | 1411 // Lookup the property locally in the receiver. |
| 1406 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { | 1412 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { |
| 1407 LookupResult lookup; | 1413 LookupResult lookup; |
| 1408 | 1414 |
| 1409 if (LookupForWrite(*receiver, *name, &lookup)) { | 1415 if (LookupForWrite(*receiver, *name, &lookup)) { |
| 1410 bool can_be_inlined = | 1416 bool can_be_inlined = |
| 1411 state == UNINITIALIZED && | 1417 state == UNINITIALIZED && |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1449 if (FLAG_trace_ic) { | 1455 if (FLAG_trace_ic) { |
| 1450 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", | 1456 PrintF("[StoreIC : no inline patch %s (not inlinable)]\n", |
| 1451 *name->ToCString()); | 1457 *name->ToCString()); |
| 1452 #endif | 1458 #endif |
| 1453 } | 1459 } |
| 1454 } | 1460 } |
| 1455 } | 1461 } |
| 1456 | 1462 |
| 1457 // If no inlined store ic was patched, generate a stub for this | 1463 // If no inlined store ic was patched, generate a stub for this |
| 1458 // store. | 1464 // store. |
| 1459 UpdateCaches(&lookup, state, receiver, name, value); | 1465 UpdateCaches(&lookup, state, extra_ic_state, receiver, name, value); |
| 1466 } else { |
| 1467 // Strict mode doesn't allow setting non-existent global property. |
| 1468 if (extra_ic_state == kStoreICStrict && IsContextual(object)) { |
| 1469 return ReferenceError("not_defined", name); |
| 1470 } |
| 1460 } | 1471 } |
| 1461 } | 1472 } |
| 1462 | 1473 |
| 1463 if (receiver->IsJSGlobalProxy()) { | 1474 if (receiver->IsJSGlobalProxy()) { |
| 1464 // Generate a generic stub that goes to the runtime when we see a global | 1475 // Generate a generic stub that goes to the runtime when we see a global |
| 1465 // proxy as receiver. | 1476 // proxy as receiver. |
| 1466 if (target() != global_proxy_stub()) { | 1477 Code* stub = (extra_ic_state == kStoreICStrict) |
| 1467 set_target(global_proxy_stub()); | 1478 ? global_proxy_stub_strict() |
| 1479 : global_proxy_stub(); |
| 1480 if (target() != stub) { |
| 1481 set_target(stub); |
| 1468 #ifdef DEBUG | 1482 #ifdef DEBUG |
| 1469 TraceIC("StoreIC", name, state, target()); | 1483 TraceIC("StoreIC", name, state, target()); |
| 1470 #endif | 1484 #endif |
| 1471 } | 1485 } |
| 1472 } | 1486 } |
| 1473 | 1487 |
| 1474 // Set the property. | 1488 // Set the property. |
| 1475 return receiver->SetProperty(*name, *value, NONE); | 1489 return receiver->SetProperty(*name, *value, NONE); |
| 1476 } | 1490 } |
| 1477 | 1491 |
| 1478 | 1492 |
| 1479 void StoreIC::UpdateCaches(LookupResult* lookup, | 1493 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1480 State state, | 1494 State state, |
| 1495 Code::ExtraICState extra_ic_state, |
| 1481 Handle<JSObject> receiver, | 1496 Handle<JSObject> receiver, |
| 1482 Handle<String> name, | 1497 Handle<String> name, |
| 1483 Handle<Object> value) { | 1498 Handle<Object> value) { |
| 1484 // Skip JSGlobalProxy. | 1499 // Skip JSGlobalProxy. |
| 1485 ASSERT(!receiver->IsJSGlobalProxy()); | 1500 ASSERT(!receiver->IsJSGlobalProxy()); |
| 1486 | 1501 |
| 1487 ASSERT(StoreICableLookup(lookup)); | 1502 ASSERT(StoreICableLookup(lookup)); |
| 1488 | 1503 |
| 1489 // If the property has a non-field type allowing map transitions | 1504 // If the property has a non-field type allowing map transitions |
| 1490 // where there is extra room in the object, we leave the IC in its | 1505 // where there is extra room in the object, we leave the IC in its |
| 1491 // current state. | 1506 // current state. |
| 1492 PropertyType type = lookup->type(); | 1507 PropertyType type = lookup->type(); |
| 1493 | 1508 |
| 1494 // Compute the code stub for this store; used for rewriting to | 1509 // Compute the code stub for this store; used for rewriting to |
| 1495 // monomorphic state and making sure that the code stub is in the | 1510 // monomorphic state and making sure that the code stub is in the |
| 1496 // stub cache. | 1511 // stub cache. |
| 1497 MaybeObject* maybe_code = NULL; | 1512 MaybeObject* maybe_code = NULL; |
| 1498 Object* code = NULL; | 1513 Object* code = NULL; |
| 1499 switch (type) { | 1514 switch (type) { |
| 1500 case FIELD: { | 1515 case FIELD: { |
| 1501 maybe_code = StubCache::ComputeStoreField(*name, *receiver, | 1516 maybe_code = StubCache::ComputeStoreField( |
| 1502 lookup->GetFieldIndex()); | 1517 *name, *receiver, lookup->GetFieldIndex(), NULL, extra_ic_state); |
| 1503 break; | 1518 break; |
| 1504 } | 1519 } |
| 1505 case MAP_TRANSITION: { | 1520 case MAP_TRANSITION: { |
| 1506 if (lookup->GetAttributes() != NONE) return; | 1521 if (lookup->GetAttributes() != NONE) return; |
| 1507 HandleScope scope; | 1522 HandleScope scope; |
| 1508 ASSERT(type == MAP_TRANSITION); | 1523 ASSERT(type == MAP_TRANSITION); |
| 1509 Handle<Map> transition(lookup->GetTransitionMap()); | 1524 Handle<Map> transition(lookup->GetTransitionMap()); |
| 1510 int index = transition->PropertyIndexFor(*name); | 1525 int index = transition->PropertyIndexFor(*name); |
| 1511 maybe_code = StubCache::ComputeStoreField(*name, *receiver, | 1526 maybe_code = StubCache::ComputeStoreField( |
| 1512 index, *transition); | 1527 *name, *receiver, index, *transition, extra_ic_state); |
| 1513 break; | 1528 break; |
| 1514 } | 1529 } |
| 1515 case NORMAL: { | 1530 case NORMAL: { |
| 1516 if (receiver->IsGlobalObject()) { | 1531 if (receiver->IsGlobalObject()) { |
| 1517 // The stub generated for the global object picks the value directly | 1532 // The stub generated for the global object picks the value directly |
| 1518 // from the property cell. So the property must be directly on the | 1533 // from the property cell. So the property must be directly on the |
| 1519 // global object. | 1534 // global object. |
| 1520 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1535 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1521 JSGlobalPropertyCell* cell = | 1536 JSGlobalPropertyCell* cell = |
| 1522 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); | 1537 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); |
| 1523 maybe_code = StubCache::ComputeStoreGlobal(*name, *global, cell); | 1538 maybe_code = StubCache::ComputeStoreGlobal( |
| 1539 *name, *global, cell, extra_ic_state); |
| 1524 } else { | 1540 } else { |
| 1525 if (lookup->holder() != *receiver) return; | 1541 if (lookup->holder() != *receiver) return; |
| 1526 maybe_code = StubCache::ComputeStoreNormal(); | 1542 maybe_code = StubCache::ComputeStoreNormal(extra_ic_state); |
| 1527 } | 1543 } |
| 1528 break; | 1544 break; |
| 1529 } | 1545 } |
| 1530 case CALLBACKS: { | 1546 case CALLBACKS: { |
| 1531 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; | 1547 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; |
| 1532 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1548 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
| 1533 if (v8::ToCData<Address>(callback->setter()) == 0) return; | 1549 if (v8::ToCData<Address>(callback->setter()) == 0) return; |
| 1534 maybe_code = StubCache::ComputeStoreCallback(*name, *receiver, callback); | 1550 maybe_code = StubCache::ComputeStoreCallback( |
| 1551 *name, *receiver, callback, extra_ic_state); |
| 1535 break; | 1552 break; |
| 1536 } | 1553 } |
| 1537 case INTERCEPTOR: { | 1554 case INTERCEPTOR: { |
| 1538 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1555 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
| 1539 maybe_code = StubCache::ComputeStoreInterceptor(*name, *receiver); | 1556 maybe_code = StubCache::ComputeStoreInterceptor( |
| 1557 *name, *receiver, extra_ic_state); |
| 1540 break; | 1558 break; |
| 1541 } | 1559 } |
| 1542 default: | 1560 default: |
| 1543 return; | 1561 return; |
| 1544 } | 1562 } |
| 1545 | 1563 |
| 1546 // If we're unable to compute the stub (not enough memory left), we | 1564 // If we're unable to compute the stub (not enough memory left), we |
| 1547 // simply avoid updating the caches. | 1565 // simply avoid updating the caches. |
| 1548 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; | 1566 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return; |
| 1549 | 1567 |
| 1550 // Patch the call site depending on the state of the cache. | 1568 // Patch the call site depending on the state of the cache. |
| 1551 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { | 1569 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
| 1552 set_target(Code::cast(code)); | 1570 set_target(Code::cast(code)); |
| 1553 } else if (state == MONOMORPHIC) { | 1571 } else if (state == MONOMORPHIC) { |
| 1554 // Only move to megamorphic if the target changes. | 1572 // Only move to megamorphic if the target changes. |
| 1555 if (target() != Code::cast(code)) set_target(megamorphic_stub()); | 1573 if (target() != Code::cast(code)) { |
| 1574 set_target(extra_ic_state == kStoreICStrict |
| 1575 ? megamorphic_stub_strict() |
| 1576 : megamorphic_stub()); |
| 1577 } |
| 1556 } else if (state == MEGAMORPHIC) { | 1578 } else if (state == MEGAMORPHIC) { |
| 1557 // Update the stub cache. | 1579 // Update the stub cache. |
| 1558 StubCache::Set(*name, receiver->map(), Code::cast(code)); | 1580 StubCache::Set(*name, receiver->map(), Code::cast(code)); |
| 1559 } | 1581 } |
| 1560 | 1582 |
| 1561 #ifdef DEBUG | 1583 #ifdef DEBUG |
| 1562 TraceIC("StoreIC", name, state, target()); | 1584 TraceIC("StoreIC", name, state, target()); |
| 1563 #endif | 1585 #endif |
| 1564 } | 1586 } |
| 1565 | 1587 |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1788 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); | 1810 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); |
| 1789 } | 1811 } |
| 1790 | 1812 |
| 1791 | 1813 |
| 1792 // Used from ic-<arch>.cc. | 1814 // Used from ic-<arch>.cc. |
| 1793 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { | 1815 MUST_USE_RESULT MaybeObject* StoreIC_Miss(Arguments args) { |
| 1794 NoHandleAllocation na; | 1816 NoHandleAllocation na; |
| 1795 ASSERT(args.length() == 3); | 1817 ASSERT(args.length() == 3); |
| 1796 StoreIC ic; | 1818 StoreIC ic; |
| 1797 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); | 1819 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1798 return ic.Store(state, args.at<Object>(0), args.at<String>(1), | 1820 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
| 1799 args.at<Object>(2)); | 1821 return ic.Store(state, extra_ic_state, args.at<Object>(0), |
| 1822 args.at<String>(1), args.at<Object>(2)); |
| 1800 } | 1823 } |
| 1801 | 1824 |
| 1802 | 1825 |
| 1803 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { | 1826 MUST_USE_RESULT MaybeObject* StoreIC_ArrayLength(Arguments args) { |
| 1804 NoHandleAllocation nha; | 1827 NoHandleAllocation nha; |
| 1805 | 1828 |
| 1806 ASSERT(args.length() == 2); | 1829 ASSERT(args.length() == 2); |
| 1807 JSObject* receiver = JSObject::cast(args[0]); | 1830 JSObject* receiver = JSObject::cast(args[0]); |
| 1808 Object* len = args[1]; | 1831 Object* len = args[1]; |
| 1809 | 1832 |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2257 #undef ADDR | 2280 #undef ADDR |
| 2258 }; | 2281 }; |
| 2259 | 2282 |
| 2260 | 2283 |
| 2261 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2284 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2262 return IC_utilities[id]; | 2285 return IC_utilities[id]; |
| 2263 } | 2286 } |
| 2264 | 2287 |
| 2265 | 2288 |
| 2266 } } // namespace v8::internal | 2289 } } // namespace v8::internal |
| OLD | NEW |