Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1558)

Side by Side Diff: src/ic.cc

Issue 12810006: Change LookupForWrite to always do a full lookup and check the result. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/stub-cache-ia32.cc ('k') | src/property.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ia32/stub-cache-ia32.cc ('k') | src/property.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698