| 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());
|
|
|