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

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: Check callbacks in the prototype chain before looking for transitions. Fix !IsReadOnly 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
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;
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ia32/stub-cache-ia32.cc ('k') | src/property.h » ('j') | test/mjsunit/regress/readonly1.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698