Index: src/ic.cc |
diff --git a/src/ic.cc b/src/ic.cc |
index 5d6f1f18751ff33f115571195b3b78155635942d..b90436ae42c5f38feed72cf4d44be0d6f6b8b04f 100644 |
--- a/src/ic.cc |
+++ b/src/ic.cc |
@@ -351,11 +351,9 @@ void IC::Clear(Address address) { |
switch (target->kind()) { |
case Code::LOAD_IC: return LoadIC::Clear(address, target); |
- case Code::KEYED_LOAD_IC: |
- return KeyedLoadIC::Clear(address, target); |
+ case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); |
case Code::STORE_IC: return StoreIC::Clear(address, target); |
- case Code::KEYED_STORE_IC: |
- return KeyedStoreIC::Clear(address, target); |
+ case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); |
case Code::CALL_IC: return CallIC::Clear(address, target); |
case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); |
case Code::COMPARE_IC: return CompareIC::Clear(address, target); |
@@ -387,13 +385,13 @@ void KeyedLoadIC::Clear(Address address, Code* target) { |
// Make sure to also clear the map used in inline fast cases. If we |
// do not clear these maps, cached code can keep objects alive |
// through the embedded maps. |
- SetTargetAtAddress(address, initialize_stub()); |
+ SetTargetAtAddress(address, *initialize_stub()); |
} |
void LoadIC::Clear(Address address, Code* target) { |
if (target->ic_state() == UNINITIALIZED) return; |
- SetTargetAtAddress(address, initialize_stub()); |
+ SetTargetAtAddress(address, *initialize_stub()); |
} |
@@ -401,8 +399,8 @@ void StoreIC::Clear(Address address, Code* target) { |
if (target->ic_state() == UNINITIALIZED) return; |
SetTargetAtAddress(address, |
(Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) |
- ? initialize_stub_strict() |
- : initialize_stub()); |
+ ? *initialize_stub_strict() |
+ : *initialize_stub()); |
} |
@@ -410,8 +408,8 @@ void KeyedStoreIC::Clear(Address address, Code* target) { |
if (target->ic_state() == UNINITIALIZED) return; |
SetTargetAtAddress(address, |
(Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) |
- ? initialize_stub_strict() |
- : initialize_stub()); |
+ ? *initialize_stub_strict() |
+ : *initialize_stub()); |
} |
@@ -1313,34 +1311,34 @@ static bool LookupForWrite(Handle<JSObject> receiver, |
} |
-MaybeObject* StoreIC::Store(State state, |
- StrictModeFlag strict_mode, |
- Handle<Object> object, |
- Handle<String> name, |
- Handle<Object> value) { |
- if (!object->IsJSObject()) { |
- // Handle proxies. |
- if (object->IsJSProxy()) { |
- return JSProxy::cast(*object)-> |
- SetProperty(*name, *value, NONE, strict_mode); |
- } |
+MaybeObject* IC::Store(State state, |
+ StrictModeFlag strict_mode, |
+ Handle<Object> object, |
+ Handle<String> name, |
+ Handle<Object> value, |
+ JSReceiver::StoreFromKeyed store_mode) { |
+ // Handle proxies. |
+ if (object->IsJSProxy()) { |
+ return JSProxy::cast(*object)-> |
+ SetProperty(*name, *value, NONE, strict_mode); |
+ } |
- // If the object is undefined or null it's illegal to try to set any |
- // properties on it; throw a TypeError in that case. |
- if (object->IsUndefined() || object->IsNull()) { |
- return TypeError("non_object_property_store", object, name); |
- } |
+ // If the object is undefined or null it's illegal to try to set any |
+ // properties on it; throw a TypeError in that case. |
+ if (object->IsUndefined() || object->IsNull()) { |
+ return TypeError("non_object_property_store", object, name); |
+ } |
- // The length property of string values is read-only. Throw in strict mode. |
- if (strict_mode == kStrictMode && object->IsString() && |
- name->Equals(isolate()->heap()->length_symbol())) { |
- return TypeError("strict_read_only_property", object, name); |
- } |
- // Ignore other stores where the receiver is not a JSObject. |
- // TODO(1475): Must check prototype chains of object wrappers. |
- return *value; |
+ // The length property of string values is read-only. Throw in strict mode. |
+ if (strict_mode == kStrictMode && object->IsString() && |
+ name->Equals(isolate()->heap()->length_symbol())) { |
+ return TypeError("strict_read_only_property", object, name); |
} |
+ // Ignore other stores where the receiver is not a JSObject. |
+ // TODO(1475): Must check prototype chains of object wrappers. |
+ if (!object->IsJSObject()) return *value; |
+ |
Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
// Check if the given name is an array index. |
@@ -1354,75 +1352,63 @@ MaybeObject* StoreIC::Store(State state, |
// Observed objects are always modified through the runtime. |
if (FLAG_harmony_observation && receiver->map()->is_observed()) { |
- return receiver->SetProperty(*name, *value, NONE, strict_mode); |
+ return receiver->SetProperty(*name, *value, NONE, strict_mode, store_mode); |
} |
// Use specialized code for setting the length of arrays with fast |
- // properties. Slow properties might indicate redefinition of the |
- // length property. |
- if (receiver->IsJSArray() && |
+ // properties. Slow properties might indicate redefinition of the length |
+ // property. |
+ if (FLAG_use_ic && |
+ receiver->IsJSArray() && |
name->Equals(isolate()->heap()->length_symbol()) && |
Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && |
- receiver->HasFastProperties()) { |
-#ifdef DEBUG |
- if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); |
-#endif |
+ receiver->HasFastProperties() && |
+ kind() != Code::KEYED_STORE_IC) { |
Handle<Code> stub = (strict_mode == kStrictMode) |
? isolate()->builtins()->StoreIC_ArrayLength_Strict() |
: isolate()->builtins()->StoreIC_ArrayLength(); |
set_target(*stub); |
- return receiver->SetProperty(*name, *value, NONE, strict_mode); |
+ TRACE_IC("StoreIC", name, state, *stub); |
+ return receiver->SetProperty(*name, *value, NONE, strict_mode, store_mode); |
} |
- // Lookup the property locally in the receiver. |
- if (!receiver->IsJSGlobalProxy()) { |
- LookupResult lookup(isolate()); |
- |
- if (LookupForWrite(receiver, name, &lookup)) { |
- if (FLAG_use_ic) { // Generate a stub for this store. |
- UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
- } |
- } else { |
- // Strict mode doesn't allow setting non-existent global property |
- // or an assignment to a read only property. |
- if (strict_mode == kStrictMode) { |
- if (lookup.IsProperty() && lookup.IsReadOnly()) { |
- return TypeError("strict_read_only_property", object, name); |
- } else if (IsContextual(object)) { |
- return ReferenceError("not_defined", name); |
- } |
- } |
+ if (receiver->IsJSGlobalProxy()) { |
+ if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) { |
+ // Generate a generic stub that goes to the runtime when we see a global |
+ // proxy as receiver. |
+ Handle<Code> stub = (strict_mode == kStrictMode) |
+ ? global_proxy_stub_strict() |
+ : global_proxy_stub(); |
+ set_target(*stub); |
+ TRACE_IC("StoreIC", name, state, *stub); |
} |
+ return receiver->SetProperty(*name, *value, NONE, strict_mode, store_mode); |
} |
- if (receiver->IsJSGlobalProxy()) { |
- // TODO(ulan): find out why we patch this site even with --no-use-ic |
- // Generate a generic stub that goes to the runtime when we see a global |
- // proxy as receiver. |
- Handle<Code> stub = (strict_mode == kStrictMode) |
- ? global_proxy_stub_strict() |
- : global_proxy_stub(); |
- if (target() != *stub) { |
- set_target(*stub); |
- TRACE_IC("StoreIC", name, state, target()); |
+ LookupResult lookup(isolate()); |
+ if (LookupForWrite(receiver, name, &lookup)) { |
+ if (FLAG_use_ic) { |
+ UpdateStoreCaches(&lookup, state, strict_mode, receiver, name, value); |
} |
+ } else if (strict_mode == kStrictMode && |
+ !lookup.IsFound() && |
+ IsContextual(object)) { |
+ // Strict mode doesn't allow setting non-existent global property |
+ // or an assignment to a read only property. |
+ return ReferenceError("not_defined", name); |
} |
// Set the property. |
- return receiver->SetProperty(*name, |
- *value, |
- NONE, |
- strict_mode, |
- JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED); |
+ return receiver->SetProperty(*name, *value, NONE, strict_mode, store_mode); |
} |
-void StoreIC::UpdateCaches(LookupResult* lookup, |
- State state, |
- StrictModeFlag strict_mode, |
- Handle<JSObject> receiver, |
- Handle<String> name, |
- Handle<Object> value) { |
+void StoreIC::UpdateStoreCaches(LookupResult* lookup, |
+ State state, |
+ StrictModeFlag strict_mode, |
+ Handle<JSObject> receiver, |
+ Handle<String> name, |
+ Handle<Object> value) { |
ASSERT(!receiver->IsJSGlobalProxy()); |
ASSERT(StoreICableLookup(lookup)); |
ASSERT(lookup->IsFound()); |
@@ -1531,7 +1517,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup, |
} |
isolate()->stub_cache()->Set(*name, receiver->map(), *code); |
set_target((strict_mode == kStrictMode) |
- ? megamorphic_stub_strict() |
+ ? *megamorphic_stub_strict() |
: *megamorphic_stub()); |
} |
break; |
@@ -1891,43 +1877,12 @@ MaybeObject* KeyedStoreIC::Store(State state, |
if (key->IsSymbol()) { |
Handle<String> name = Handle<String>::cast(key); |
- |
- // Handle proxies. |
- if (object->IsJSProxy()) { |
- return JSProxy::cast(*object)->SetProperty( |
- *name, *value, NONE, strict_mode); |
- } |
- |
- // If the object is undefined or null it's illegal to try to set any |
- // properties on it; throw a TypeError in that case. |
- if (object->IsUndefined() || object->IsNull()) { |
- return TypeError("non_object_property_store", object, name); |
- } |
- |
- // Ignore stores where the receiver is not a JSObject. |
- if (!object->IsJSObject()) return *value; |
- Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
- |
- // Check if the given name is an array index. |
- uint32_t index; |
- if (name->AsArrayIndex(&index)) { |
- Handle<Object> result = |
- JSObject::SetElement(receiver, index, value, NONE, strict_mode); |
- RETURN_IF_EMPTY_HANDLE(isolate(), result); |
- return *value; |
- } |
- |
- // Update inline cache and stub cache. |
- if (FLAG_use_ic && !receiver->IsJSGlobalProxy() && |
- !(FLAG_harmony_observation && receiver->map()->is_observed())) { |
- LookupResult lookup(isolate()); |
- if (LookupForWrite(receiver, name, &lookup)) { |
- UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
- } |
- } |
- |
- // Set the property. |
- return receiver->SetProperty(*name, *value, NONE, strict_mode); |
+ return IC::Store(state, |
+ strict_mode, |
+ object, |
+ name, |
+ value, |
+ JSReceiver::MAY_BE_STORE_FROM_KEYED); |
} |
// Do not use ICs for objects that require access checks (including |
@@ -1966,12 +1921,12 @@ MaybeObject* KeyedStoreIC::Store(State state, |
} |
-void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
- State state, |
- StrictModeFlag strict_mode, |
- Handle<JSObject> receiver, |
- Handle<String> name, |
- Handle<Object> value) { |
+void KeyedStoreIC::UpdateStoreCaches(LookupResult* lookup, |
+ State state, |
+ StrictModeFlag strict_mode, |
+ Handle<JSObject> receiver, |
+ Handle<String> name, |
+ Handle<Object> value) { |
ASSERT(!receiver->IsJSGlobalProxy()); |
ASSERT(StoreICableLookup(lookup)); |
ASSERT(lookup->IsFound()); |