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 |