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 |