| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index c1d11bbb90678b646f8904673d61e3874f0bb872..114235ea0eb2aa8ff62c2a5e8ccf89a3fbd9d396 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -1418,41 +1418,42 @@ Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup,
|
| }
|
|
|
|
|
| -static bool StoreICableLookup(LookupResult* lookup) {
|
| - // Bail out if we didn't find a result.
|
| - if (!lookup->IsFound()) return false;
|
| -
|
| - // Bail out if inline caching is not allowed.
|
| - if (!lookup->IsCacheable()) return false;
|
| -
|
| - // If the property is read-only, we leave the IC in its current state.
|
| - if (lookup->IsTransition()) {
|
| - return !lookup->GetTransitionDetails().IsReadOnly();
|
| - }
|
| - return !lookup->IsReadOnly();
|
| -}
|
| -
|
| -
|
| static bool LookupForWrite(Handle<JSObject> receiver,
|
| Handle<String> name,
|
| LookupResult* lookup) {
|
| - receiver->LocalLookup(*name, lookup);
|
| - if (!lookup->IsFound()) {
|
| - receiver->map()->LookupTransition(*receiver, *name, lookup);
|
| - }
|
| - if (!StoreICableLookup(lookup)) {
|
| - // 2nd chance: There can be accessors somewhere in the prototype chain.
|
| - receiver->Lookup(*name, lookup);
|
| - return lookup->IsPropertyCallbacks() && StoreICableLookup(lookup);
|
| - }
|
| + Handle<JSObject> holder = receiver;
|
| + receiver->Lookup(*name, lookup);
|
| + if (lookup->IsFound()) {
|
| + if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
|
| +
|
| + if (lookup->holder() == *receiver) {
|
| + if (lookup->IsInterceptor() &&
|
| + receiver->GetNamedInterceptor()->setter()->IsUndefined()) {
|
| + receiver->LocalLookupRealNamedProperty(*name, lookup);
|
| + return lookup->IsFound() &&
|
| + !lookup->IsReadOnly() &&
|
| + lookup->IsCacheable();
|
| + }
|
| + return true;
|
| + }
|
|
|
| - if (lookup->IsInterceptor() &&
|
| - receiver->GetNamedInterceptor()->setter()->IsUndefined()) {
|
| - receiver->LocalLookupRealNamedProperty(*name, lookup);
|
| - return StoreICableLookup(lookup);
|
| + if (lookup->IsPropertyCallbacks()) return true;
|
| +
|
| + // Currently normal holders in the prototype chain are not supported. They
|
| + // would require a runtime positive lookup and verification that the details
|
| + // have not changed.
|
| + if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
|
| + holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
|
| }
|
|
|
| - return true;
|
| + // While normally LookupTransition gets passed the receiver, in this case we
|
| + // pass the holder of the property that we overwrite. This keeps the holder in
|
| + // the LookupResult intact so we can later use it to generate a prototype
|
| + // chain check. This avoids a double lookup, but requires us to pass in the
|
| + // receiver when trying to fetch extra information from the transition.
|
| + receiver->map()->LookupTransition(*holder, *name, lookup);
|
| + return lookup->IsTransition() &&
|
| + !lookup->GetTransitionDetails(receiver->map()).IsReadOnly();
|
| }
|
|
|
|
|
| @@ -1552,7 +1553,6 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
| Handle<String> name,
|
| Handle<Object> value) {
|
| ASSERT(!receiver->IsJSGlobalProxy());
|
| - ASSERT(StoreICableLookup(lookup));
|
| ASSERT(lookup->IsFound());
|
|
|
| // These are not cacheable, so we never see such LookupResults here.
|
| @@ -1575,8 +1575,7 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
|
| switch (lookup->type()) {
|
| case FIELD:
|
| return isolate()->stub_cache()->ComputeStoreField(
|
| - name, receiver, lookup->GetFieldIndex().field_index(),
|
| - Handle<Map>::null(), strict_mode);
|
| + name, receiver, lookup, Handle<Map>::null(), strict_mode);
|
| case NORMAL:
|
| if (receiver->IsGlobalObject()) {
|
| // The stub generated for the global object picks the value directly
|
| @@ -1588,7 +1587,7 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
|
| return isolate()->stub_cache()->ComputeStoreGlobal(
|
| name, global, cell, strict_mode);
|
| }
|
| - if (!holder.is_identical_to(receiver)) break;
|
| + ASSERT(holder.is_identical_to(receiver));
|
| return isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
|
| case CALLBACKS: {
|
| Handle<Object> callback(lookup->GetCallbackObject(), isolate());
|
| @@ -1623,7 +1622,10 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
|
| case CONSTANT_FUNCTION:
|
| break;
|
| case TRANSITION: {
|
| - Handle<Map> transition(lookup->GetTransitionTarget(), isolate());
|
| + // Explicitly pass in the receiver map since LookupForWrite may have
|
| + // stored something else than the receiver in the holder.
|
| + Handle<Map> transition(
|
| + lookup->GetTransitionTarget(receiver->map()), isolate());
|
| int descriptor = transition->LastAdded();
|
|
|
| DescriptorArray* target_descriptors = transition->instance_descriptors();
|
| @@ -1631,9 +1633,8 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
|
|
|
| if (details.type() != FIELD || details.attributes() != NONE) break;
|
|
|
| - int field_index = target_descriptors->GetFieldIndex(descriptor);
|
| return isolate()->stub_cache()->ComputeStoreField(
|
| - name, receiver, field_index, transition, strict_mode);
|
| + name, receiver, lookup, transition, strict_mode);
|
| }
|
| case NONEXISTENT:
|
| case HANDLER:
|
| @@ -1964,19 +1965,20 @@ Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
|
| switch (lookup->type()) {
|
| case FIELD:
|
| return isolate()->stub_cache()->ComputeKeyedStoreField(
|
| - name, receiver, lookup->GetFieldIndex().field_index(),
|
| - Handle<Map>::null(), strict_mode);
|
| + name, receiver, lookup, Handle<Map>::null(), strict_mode);
|
| case TRANSITION: {
|
| - Handle<Map> transition(lookup->GetTransitionTarget(), isolate());
|
| + // Explicitly pass in the receiver map since LookupForWrite may have
|
| + // stored something else than the receiver in the holder.
|
| + Handle<Map> transition(
|
| + lookup->GetTransitionTarget(receiver->map()), isolate());
|
| int descriptor = transition->LastAdded();
|
|
|
| DescriptorArray* target_descriptors = transition->instance_descriptors();
|
| PropertyDetails details = target_descriptors->GetDetails(descriptor);
|
|
|
| if (details.type() == FIELD && details.attributes() == NONE) {
|
| - int field_index = target_descriptors->GetFieldIndex(descriptor);
|
| return isolate()->stub_cache()->ComputeKeyedStoreField(
|
| - name, receiver, field_index, transition, strict_mode);
|
| + name, receiver, lookup, transition, strict_mode);
|
| }
|
| // fall through.
|
| }
|
|
|