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 1400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1411 name, receiver, holder); | 1411 name, receiver, holder); |
1412 default: | 1412 default: |
1413 // Always rewrite to the generic case so that we do not | 1413 // Always rewrite to the generic case so that we do not |
1414 // repeatedly try to rewrite. | 1414 // repeatedly try to rewrite. |
1415 return generic_stub(); | 1415 return generic_stub(); |
1416 } | 1416 } |
1417 return Handle<Code>::null(); | 1417 return Handle<Code>::null(); |
1418 } | 1418 } |
1419 | 1419 |
1420 | 1420 |
1421 static bool StoreICableLookup(LookupResult* lookup) { | |
1422 // Bail out if we didn't find a result. | |
1423 if (!lookup->IsFound()) return false; | |
1424 | |
1425 // Bail out if inline caching is not allowed. | |
1426 if (!lookup->IsCacheable()) return false; | |
1427 | |
1428 // If the property is read-only, we leave the IC in its current state. | |
1429 if (lookup->IsTransition()) { | |
1430 return !lookup->GetTransitionDetails().IsReadOnly(); | |
1431 } | |
1432 return !lookup->IsReadOnly(); | |
1433 } | |
1434 | |
1435 | |
1436 static bool LookupForWrite(Handle<JSObject> receiver, | 1421 static bool LookupForWrite(Handle<JSObject> receiver, |
1437 Handle<String> name, | 1422 Handle<String> name, |
1438 LookupResult* lookup) { | 1423 LookupResult* lookup) { |
1439 receiver->LocalLookup(*name, lookup); | 1424 Handle<JSObject> holder = receiver; |
1440 if (!lookup->IsFound()) { | 1425 receiver->Lookup(*name, lookup); |
1441 receiver->map()->LookupTransition(*receiver, *name, lookup); | 1426 if (lookup->IsFound()) { |
1442 } | 1427 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; |
1443 if (!StoreICableLookup(lookup)) { | 1428 |
1444 // 2nd chance: There can be accessors somewhere in the prototype chain. | 1429 if (lookup->holder() == *receiver) { |
1445 receiver->Lookup(*name, lookup); | 1430 if (lookup->IsInterceptor() && |
1446 return lookup->IsPropertyCallbacks() && StoreICableLookup(lookup); | 1431 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { |
| 1432 receiver->LocalLookupRealNamedProperty(*name, lookup); |
| 1433 return lookup->IsFound() && |
| 1434 !lookup->IsReadOnly() && |
| 1435 lookup->IsCacheable(); |
| 1436 } |
| 1437 return true; |
| 1438 } |
| 1439 |
| 1440 if (lookup->IsPropertyCallbacks()) return true; |
| 1441 |
| 1442 // Currently normal holders in the prototype chain are not supported. They |
| 1443 // would require a runtime positive lookup and verification that the details |
| 1444 // have not changed. |
| 1445 if (lookup->IsInterceptor() || lookup->IsNormal()) return false; |
| 1446 holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); |
1447 } | 1447 } |
1448 | 1448 |
1449 if (lookup->IsInterceptor() && | 1449 // While normally LookupTransition gets passed the receiver, in this case we |
1450 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { | 1450 // pass the holder of the property that we overwrite. This keeps the holder in |
1451 receiver->LocalLookupRealNamedProperty(*name, lookup); | 1451 // the LookupResult intact so we can later use it to generate a prototype |
1452 return StoreICableLookup(lookup); | 1452 // chain check. This avoids a double lookup, but requires us to pass in the |
1453 } | 1453 // receiver when trying to fetch extra information from the transition. |
1454 | 1454 receiver->map()->LookupTransition(*holder, *name, lookup); |
1455 return true; | 1455 return lookup->IsTransition() && |
| 1456 !lookup->GetTransitionDetails(receiver->map()).IsReadOnly(); |
1456 } | 1457 } |
1457 | 1458 |
1458 | 1459 |
1459 MaybeObject* StoreIC::Store(State state, | 1460 MaybeObject* StoreIC::Store(State state, |
1460 StrictModeFlag strict_mode, | 1461 StrictModeFlag strict_mode, |
1461 Handle<Object> object, | 1462 Handle<Object> object, |
1462 Handle<String> name, | 1463 Handle<String> name, |
1463 Handle<Object> value, | 1464 Handle<Object> value, |
1464 JSReceiver::StoreFromKeyed store_mode) { | 1465 JSReceiver::StoreFromKeyed store_mode) { |
1465 // Handle proxies. | 1466 // Handle proxies. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1545 } | 1546 } |
1546 | 1547 |
1547 | 1548 |
1548 void StoreIC::UpdateCaches(LookupResult* lookup, | 1549 void StoreIC::UpdateCaches(LookupResult* lookup, |
1549 State state, | 1550 State state, |
1550 StrictModeFlag strict_mode, | 1551 StrictModeFlag strict_mode, |
1551 Handle<JSObject> receiver, | 1552 Handle<JSObject> receiver, |
1552 Handle<String> name, | 1553 Handle<String> name, |
1553 Handle<Object> value) { | 1554 Handle<Object> value) { |
1554 ASSERT(!receiver->IsJSGlobalProxy()); | 1555 ASSERT(!receiver->IsJSGlobalProxy()); |
1555 ASSERT(StoreICableLookup(lookup)); | |
1556 ASSERT(lookup->IsFound()); | 1556 ASSERT(lookup->IsFound()); |
1557 | 1557 |
1558 // These are not cacheable, so we never see such LookupResults here. | 1558 // These are not cacheable, so we never see such LookupResults here. |
1559 ASSERT(!lookup->IsHandler()); | 1559 ASSERT(!lookup->IsHandler()); |
1560 | 1560 |
1561 Handle<Code> code = | 1561 Handle<Code> code = |
1562 ComputeStoreMonomorphic(lookup, strict_mode, receiver, name); | 1562 ComputeStoreMonomorphic(lookup, strict_mode, receiver, name); |
1563 if (code.is_null()) return; | 1563 if (code.is_null()) return; |
1564 | 1564 |
1565 PatchCache(state, strict_mode, receiver, name, code); | 1565 PatchCache(state, strict_mode, receiver, name, code); |
1566 TRACE_IC("StoreIC", name, state, target()); | 1566 TRACE_IC("StoreIC", name, state, target()); |
1567 } | 1567 } |
1568 | 1568 |
1569 | 1569 |
1570 Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, | 1570 Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, |
1571 StrictModeFlag strict_mode, | 1571 StrictModeFlag strict_mode, |
1572 Handle<JSObject> receiver, | 1572 Handle<JSObject> receiver, |
1573 Handle<String> name) { | 1573 Handle<String> name) { |
1574 Handle<JSObject> holder(lookup->holder()); | 1574 Handle<JSObject> holder(lookup->holder()); |
1575 switch (lookup->type()) { | 1575 switch (lookup->type()) { |
1576 case FIELD: | 1576 case FIELD: |
1577 return isolate()->stub_cache()->ComputeStoreField( | 1577 return isolate()->stub_cache()->ComputeStoreField( |
1578 name, receiver, lookup->GetFieldIndex().field_index(), | 1578 name, receiver, lookup, Handle<Map>::null(), strict_mode); |
1579 Handle<Map>::null(), strict_mode); | |
1580 case NORMAL: | 1579 case NORMAL: |
1581 if (receiver->IsGlobalObject()) { | 1580 if (receiver->IsGlobalObject()) { |
1582 // The stub generated for the global object picks the value directly | 1581 // The stub generated for the global object picks the value directly |
1583 // from the property cell. So the property must be directly on the | 1582 // from the property cell. So the property must be directly on the |
1584 // global object. | 1583 // global object. |
1585 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1584 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
1586 Handle<JSGlobalPropertyCell> cell( | 1585 Handle<JSGlobalPropertyCell> cell( |
1587 global->GetPropertyCell(lookup), isolate()); | 1586 global->GetPropertyCell(lookup), isolate()); |
1588 return isolate()->stub_cache()->ComputeStoreGlobal( | 1587 return isolate()->stub_cache()->ComputeStoreGlobal( |
1589 name, global, cell, strict_mode); | 1588 name, global, cell, strict_mode); |
1590 } | 1589 } |
1591 if (!holder.is_identical_to(receiver)) break; | 1590 ASSERT(holder.is_identical_to(receiver)); |
1592 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode); | 1591 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode); |
1593 case CALLBACKS: { | 1592 case CALLBACKS: { |
1594 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1593 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
1595 if (callback->IsExecutableAccessorInfo()) { | 1594 if (callback->IsExecutableAccessorInfo()) { |
1596 Handle<ExecutableAccessorInfo> info = | 1595 Handle<ExecutableAccessorInfo> info = |
1597 Handle<ExecutableAccessorInfo>::cast(callback); | 1596 Handle<ExecutableAccessorInfo>::cast(callback); |
1598 if (v8::ToCData<Address>(info->setter()) == 0) break; | 1597 if (v8::ToCData<Address>(info->setter()) == 0) break; |
1599 if (!holder->HasFastProperties()) break; | 1598 if (!holder->HasFastProperties()) break; |
1600 if (!info->IsCompatibleReceiver(*receiver)) break; | 1599 if (!info->IsCompatibleReceiver(*receiver)) break; |
1601 return isolate()->stub_cache()->ComputeStoreCallback( | 1600 return isolate()->stub_cache()->ComputeStoreCallback( |
(...skipping 14 matching lines...) Expand all Loading... |
1616 // No IC support for old-style native accessors. | 1615 // No IC support for old-style native accessors. |
1617 break; | 1616 break; |
1618 } | 1617 } |
1619 case INTERCEPTOR: | 1618 case INTERCEPTOR: |
1620 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1619 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
1621 return isolate()->stub_cache()->ComputeStoreInterceptor( | 1620 return isolate()->stub_cache()->ComputeStoreInterceptor( |
1622 name, receiver, strict_mode); | 1621 name, receiver, strict_mode); |
1623 case CONSTANT_FUNCTION: | 1622 case CONSTANT_FUNCTION: |
1624 break; | 1623 break; |
1625 case TRANSITION: { | 1624 case TRANSITION: { |
1626 Handle<Map> transition(lookup->GetTransitionTarget(), isolate()); | 1625 // Explicitly pass in the receiver map since LookupForWrite may have |
| 1626 // stored something else than the receiver in the holder. |
| 1627 Handle<Map> transition( |
| 1628 lookup->GetTransitionTarget(receiver->map()), isolate()); |
1627 int descriptor = transition->LastAdded(); | 1629 int descriptor = transition->LastAdded(); |
1628 | 1630 |
1629 DescriptorArray* target_descriptors = transition->instance_descriptors(); | 1631 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
1630 PropertyDetails details = target_descriptors->GetDetails(descriptor); | 1632 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
1631 | 1633 |
1632 if (details.type() != FIELD || details.attributes() != NONE) break; | 1634 if (details.type() != FIELD || details.attributes() != NONE) break; |
1633 | 1635 |
1634 int field_index = target_descriptors->GetFieldIndex(descriptor); | |
1635 return isolate()->stub_cache()->ComputeStoreField( | 1636 return isolate()->stub_cache()->ComputeStoreField( |
1636 name, receiver, field_index, transition, strict_mode); | 1637 name, receiver, lookup, transition, strict_mode); |
1637 } | 1638 } |
1638 case NONEXISTENT: | 1639 case NONEXISTENT: |
1639 case HANDLER: | 1640 case HANDLER: |
1640 UNREACHABLE(); | 1641 UNREACHABLE(); |
1641 break; | 1642 break; |
1642 } | 1643 } |
1643 return Handle<Code>::null(); | 1644 return Handle<Code>::null(); |
1644 } | 1645 } |
1645 | 1646 |
1646 | 1647 |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1957 Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, | 1958 Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, |
1958 StrictModeFlag strict_mode, | 1959 StrictModeFlag strict_mode, |
1959 Handle<JSObject> receiver, | 1960 Handle<JSObject> receiver, |
1960 Handle<String> name) { | 1961 Handle<String> name) { |
1961 // If the property has a non-field type allowing map transitions | 1962 // If the property has a non-field type allowing map transitions |
1962 // where there is extra room in the object, we leave the IC in its | 1963 // where there is extra room in the object, we leave the IC in its |
1963 // current state. | 1964 // current state. |
1964 switch (lookup->type()) { | 1965 switch (lookup->type()) { |
1965 case FIELD: | 1966 case FIELD: |
1966 return isolate()->stub_cache()->ComputeKeyedStoreField( | 1967 return isolate()->stub_cache()->ComputeKeyedStoreField( |
1967 name, receiver, lookup->GetFieldIndex().field_index(), | 1968 name, receiver, lookup, Handle<Map>::null(), strict_mode); |
1968 Handle<Map>::null(), strict_mode); | |
1969 case TRANSITION: { | 1969 case TRANSITION: { |
1970 Handle<Map> transition(lookup->GetTransitionTarget(), isolate()); | 1970 // Explicitly pass in the receiver map since LookupForWrite may have |
| 1971 // stored something else than the receiver in the holder. |
| 1972 Handle<Map> transition( |
| 1973 lookup->GetTransitionTarget(receiver->map()), isolate()); |
1971 int descriptor = transition->LastAdded(); | 1974 int descriptor = transition->LastAdded(); |
1972 | 1975 |
1973 DescriptorArray* target_descriptors = transition->instance_descriptors(); | 1976 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
1974 PropertyDetails details = target_descriptors->GetDetails(descriptor); | 1977 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
1975 | 1978 |
1976 if (details.type() == FIELD && details.attributes() == NONE) { | 1979 if (details.type() == FIELD && details.attributes() == NONE) { |
1977 int field_index = target_descriptors->GetFieldIndex(descriptor); | |
1978 return isolate()->stub_cache()->ComputeKeyedStoreField( | 1980 return isolate()->stub_cache()->ComputeKeyedStoreField( |
1979 name, receiver, field_index, transition, strict_mode); | 1981 name, receiver, lookup, transition, strict_mode); |
1980 } | 1982 } |
1981 // fall through. | 1983 // fall through. |
1982 } | 1984 } |
1983 case NORMAL: | 1985 case NORMAL: |
1984 case CONSTANT_FUNCTION: | 1986 case CONSTANT_FUNCTION: |
1985 case CALLBACKS: | 1987 case CALLBACKS: |
1986 case INTERCEPTOR: | 1988 case INTERCEPTOR: |
1987 // Always rewrite to the generic case so that we do not | 1989 // Always rewrite to the generic case so that we do not |
1988 // repeatedly try to rewrite. | 1990 // repeatedly try to rewrite. |
1989 return (strict_mode == kStrictMode) | 1991 return (strict_mode == kStrictMode) |
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2776 #undef ADDR | 2778 #undef ADDR |
2777 }; | 2779 }; |
2778 | 2780 |
2779 | 2781 |
2780 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2782 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2781 return IC_utilities[id]; | 2783 return IC_utilities[id]; |
2782 } | 2784 } |
2783 | 2785 |
2784 | 2786 |
2785 } } // namespace v8::internal | 2787 } } // namespace v8::internal |
OLD | NEW |