Chromium Code Reviews| 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; | |
|
rossberg
2013/03/22 14:07:44
Test case... :)
Toon Verwaest
2013/03/25 11:44:44
Done.
| |
| 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 receiver->map()->LookupTransition(*holder, *name, lookup); |
|
rossberg
2013/03/22 14:07:44
Maybe add a comment explaining why you use the hol
Toon Verwaest
2013/03/25 11:44:44
Done.
| |
| 1450 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { | 1450 return lookup->IsTransition() && |
| 1451 receiver->LocalLookupRealNamedProperty(*name, lookup); | 1451 !lookup->GetTransitionDetails(receiver->map()).IsReadOnly(); |
| 1452 return StoreICableLookup(lookup); | |
| 1453 } | |
| 1454 | |
| 1455 return true; | |
| 1456 } | 1452 } |
| 1457 | 1453 |
| 1458 | 1454 |
| 1459 MaybeObject* StoreIC::Store(State state, | 1455 MaybeObject* StoreIC::Store(State state, |
| 1460 StrictModeFlag strict_mode, | 1456 StrictModeFlag strict_mode, |
| 1461 Handle<Object> object, | 1457 Handle<Object> object, |
| 1462 Handle<String> name, | 1458 Handle<String> name, |
| 1463 Handle<Object> value, | 1459 Handle<Object> value, |
| 1464 JSReceiver::StoreFromKeyed store_mode) { | 1460 JSReceiver::StoreFromKeyed store_mode) { |
| 1465 // Handle proxies. | 1461 // Handle proxies. |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1545 } | 1541 } |
| 1546 | 1542 |
| 1547 | 1543 |
| 1548 void StoreIC::UpdateCaches(LookupResult* lookup, | 1544 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1549 State state, | 1545 State state, |
| 1550 StrictModeFlag strict_mode, | 1546 StrictModeFlag strict_mode, |
| 1551 Handle<JSObject> receiver, | 1547 Handle<JSObject> receiver, |
| 1552 Handle<String> name, | 1548 Handle<String> name, |
| 1553 Handle<Object> value) { | 1549 Handle<Object> value) { |
| 1554 ASSERT(!receiver->IsJSGlobalProxy()); | 1550 ASSERT(!receiver->IsJSGlobalProxy()); |
| 1555 ASSERT(StoreICableLookup(lookup)); | |
| 1556 ASSERT(lookup->IsFound()); | 1551 ASSERT(lookup->IsFound()); |
| 1557 | 1552 |
| 1558 // These are not cacheable, so we never see such LookupResults here. | 1553 // These are not cacheable, so we never see such LookupResults here. |
| 1559 ASSERT(!lookup->IsHandler()); | 1554 ASSERT(!lookup->IsHandler()); |
| 1560 | 1555 |
| 1561 Handle<Code> code = | 1556 Handle<Code> code = |
| 1562 ComputeStoreMonomorphic(lookup, strict_mode, receiver, name); | 1557 ComputeStoreMonomorphic(lookup, strict_mode, receiver, name); |
| 1563 if (code.is_null()) return; | 1558 if (code.is_null()) return; |
| 1564 | 1559 |
| 1565 PatchCache(state, strict_mode, receiver, name, code); | 1560 PatchCache(state, strict_mode, receiver, name, code); |
| 1566 TRACE_IC("StoreIC", name, state, target()); | 1561 TRACE_IC("StoreIC", name, state, target()); |
| 1567 } | 1562 } |
| 1568 | 1563 |
| 1569 | 1564 |
| 1570 Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, | 1565 Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, |
| 1571 StrictModeFlag strict_mode, | 1566 StrictModeFlag strict_mode, |
| 1572 Handle<JSObject> receiver, | 1567 Handle<JSObject> receiver, |
| 1573 Handle<String> name) { | 1568 Handle<String> name) { |
| 1574 Handle<JSObject> holder(lookup->holder()); | 1569 Handle<JSObject> holder(lookup->holder()); |
| 1575 switch (lookup->type()) { | 1570 switch (lookup->type()) { |
| 1576 case FIELD: | 1571 case FIELD: |
| 1577 return isolate()->stub_cache()->ComputeStoreField( | 1572 return isolate()->stub_cache()->ComputeStoreField( |
| 1578 name, receiver, lookup->GetFieldIndex().field_index(), | 1573 name, receiver, lookup, Handle<Map>::null(), strict_mode); |
| 1579 Handle<Map>::null(), strict_mode); | |
| 1580 case NORMAL: | 1574 case NORMAL: |
| 1581 if (receiver->IsGlobalObject()) { | 1575 if (receiver->IsGlobalObject()) { |
| 1582 // The stub generated for the global object picks the value directly | 1576 // The stub generated for the global object picks the value directly |
| 1583 // from the property cell. So the property must be directly on the | 1577 // from the property cell. So the property must be directly on the |
| 1584 // global object. | 1578 // global object. |
| 1585 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1579 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
| 1586 Handle<JSGlobalPropertyCell> cell( | 1580 Handle<JSGlobalPropertyCell> cell( |
| 1587 global->GetPropertyCell(lookup), isolate()); | 1581 global->GetPropertyCell(lookup), isolate()); |
| 1588 return isolate()->stub_cache()->ComputeStoreGlobal( | 1582 return isolate()->stub_cache()->ComputeStoreGlobal( |
| 1589 name, global, cell, strict_mode); | 1583 name, global, cell, strict_mode); |
| 1590 } | 1584 } |
| 1591 if (!holder.is_identical_to(receiver)) break; | |
|
rossberg
2013/03/22 14:07:44
If that's an impossible case, maybe turn it into a
Toon Verwaest
2013/03/25 11:44:44
Done.
| |
| 1592 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode); | 1585 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode); |
| 1593 case CALLBACKS: { | 1586 case CALLBACKS: { |
| 1594 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1587 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| 1595 if (callback->IsExecutableAccessorInfo()) { | 1588 if (callback->IsExecutableAccessorInfo()) { |
| 1596 Handle<ExecutableAccessorInfo> info = | 1589 Handle<ExecutableAccessorInfo> info = |
| 1597 Handle<ExecutableAccessorInfo>::cast(callback); | 1590 Handle<ExecutableAccessorInfo>::cast(callback); |
| 1598 if (v8::ToCData<Address>(info->setter()) == 0) break; | 1591 if (v8::ToCData<Address>(info->setter()) == 0) break; |
| 1599 if (!holder->HasFastProperties()) break; | 1592 if (!holder->HasFastProperties()) break; |
| 1600 if (!info->IsCompatibleReceiver(*receiver)) break; | 1593 if (!info->IsCompatibleReceiver(*receiver)) break; |
| 1601 return isolate()->stub_cache()->ComputeStoreCallback( | 1594 return isolate()->stub_cache()->ComputeStoreCallback( |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1616 // No IC support for old-style native accessors. | 1609 // No IC support for old-style native accessors. |
| 1617 break; | 1610 break; |
| 1618 } | 1611 } |
| 1619 case INTERCEPTOR: | 1612 case INTERCEPTOR: |
| 1620 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); | 1613 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
| 1621 return isolate()->stub_cache()->ComputeStoreInterceptor( | 1614 return isolate()->stub_cache()->ComputeStoreInterceptor( |
| 1622 name, receiver, strict_mode); | 1615 name, receiver, strict_mode); |
| 1623 case CONSTANT_FUNCTION: | 1616 case CONSTANT_FUNCTION: |
| 1624 break; | 1617 break; |
| 1625 case TRANSITION: { | 1618 case TRANSITION: { |
| 1626 Handle<Map> transition(lookup->GetTransitionTarget(), isolate()); | 1619 Handle<Map> transition( |
| 1620 lookup->GetTransitionTarget(receiver->map()), isolate()); | |
| 1627 int descriptor = transition->LastAdded(); | 1621 int descriptor = transition->LastAdded(); |
| 1628 | 1622 |
| 1629 DescriptorArray* target_descriptors = transition->instance_descriptors(); | 1623 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
| 1630 PropertyDetails details = target_descriptors->GetDetails(descriptor); | 1624 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
| 1631 | 1625 |
| 1632 if (details.type() != FIELD || details.attributes() != NONE) break; | 1626 if (details.type() != FIELD || details.attributes() != NONE) break; |
| 1633 | 1627 |
| 1634 int field_index = target_descriptors->GetFieldIndex(descriptor); | |
| 1635 return isolate()->stub_cache()->ComputeStoreField( | 1628 return isolate()->stub_cache()->ComputeStoreField( |
| 1636 name, receiver, field_index, transition, strict_mode); | 1629 name, receiver, lookup, transition, strict_mode); |
| 1637 } | 1630 } |
| 1638 case NONEXISTENT: | 1631 case NONEXISTENT: |
| 1639 case HANDLER: | 1632 case HANDLER: |
| 1640 UNREACHABLE(); | 1633 UNREACHABLE(); |
| 1641 break; | 1634 break; |
| 1642 } | 1635 } |
| 1643 return Handle<Code>::null(); | 1636 return Handle<Code>::null(); |
| 1644 } | 1637 } |
| 1645 | 1638 |
| 1646 | 1639 |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1957 Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, | 1950 Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, |
| 1958 StrictModeFlag strict_mode, | 1951 StrictModeFlag strict_mode, |
| 1959 Handle<JSObject> receiver, | 1952 Handle<JSObject> receiver, |
| 1960 Handle<String> name) { | 1953 Handle<String> name) { |
| 1961 // If the property has a non-field type allowing map transitions | 1954 // 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 | 1955 // where there is extra room in the object, we leave the IC in its |
| 1963 // current state. | 1956 // current state. |
| 1964 switch (lookup->type()) { | 1957 switch (lookup->type()) { |
| 1965 case FIELD: | 1958 case FIELD: |
| 1966 return isolate()->stub_cache()->ComputeKeyedStoreField( | 1959 return isolate()->stub_cache()->ComputeKeyedStoreField( |
| 1967 name, receiver, lookup->GetFieldIndex().field_index(), | 1960 name, receiver, lookup, Handle<Map>::null(), strict_mode); |
| 1968 Handle<Map>::null(), strict_mode); | |
| 1969 case TRANSITION: { | 1961 case TRANSITION: { |
| 1970 Handle<Map> transition(lookup->GetTransitionTarget(), isolate()); | 1962 Handle<Map> transition( |
| 1963 lookup->GetTransitionTarget(receiver->map()), isolate()); | |
| 1971 int descriptor = transition->LastAdded(); | 1964 int descriptor = transition->LastAdded(); |
| 1972 | 1965 |
| 1973 DescriptorArray* target_descriptors = transition->instance_descriptors(); | 1966 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
| 1974 PropertyDetails details = target_descriptors->GetDetails(descriptor); | 1967 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
| 1975 | 1968 |
| 1976 if (details.type() == FIELD && details.attributes() == NONE) { | 1969 if (details.type() == FIELD && details.attributes() == NONE) { |
| 1977 int field_index = target_descriptors->GetFieldIndex(descriptor); | |
| 1978 return isolate()->stub_cache()->ComputeKeyedStoreField( | 1970 return isolate()->stub_cache()->ComputeKeyedStoreField( |
| 1979 name, receiver, field_index, transition, strict_mode); | 1971 name, receiver, lookup, transition, strict_mode); |
| 1980 } | 1972 } |
| 1981 // fall through. | 1973 // fall through. |
| 1982 } | 1974 } |
| 1983 case NORMAL: | 1975 case NORMAL: |
| 1984 case CONSTANT_FUNCTION: | 1976 case CONSTANT_FUNCTION: |
| 1985 case CALLBACKS: | 1977 case CALLBACKS: |
| 1986 case INTERCEPTOR: | 1978 case INTERCEPTOR: |
| 1987 // Always rewrite to the generic case so that we do not | 1979 // Always rewrite to the generic case so that we do not |
| 1988 // repeatedly try to rewrite. | 1980 // repeatedly try to rewrite. |
| 1989 return (strict_mode == kStrictMode) | 1981 return (strict_mode == kStrictMode) |
| (...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2776 #undef ADDR | 2768 #undef ADDR |
| 2777 }; | 2769 }; |
| 2778 | 2770 |
| 2779 | 2771 |
| 2780 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2772 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 2781 return IC_utilities[id]; | 2773 return IC_utilities[id]; |
| 2782 } | 2774 } |
| 2783 | 2775 |
| 2784 | 2776 |
| 2785 } } // namespace v8::internal | 2777 } } // namespace v8::internal |
| OLD | NEW |