| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index 36c7e5a30a9f1a1795c54faa2c639b8f6b80f263..495c7273055e50ac77a242f511ed677b07e65d8d 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -1167,9 +1167,7 @@ static bool LookupForWrite(Handle<JSObject> receiver,
|
| // 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);
|
| - if (!lookup->IsTransition()) return false;
|
| - PropertyDetails target_details = lookup->GetTransitionDetails();
|
| - if (target_details.IsReadOnly()) return false;
|
| + if (!lookup->IsTransition() || lookup->IsReadOnly()) return false;
|
|
|
| // If the value that's being stored does not fit in the field that the
|
| // instance would transition to, create a new transition that fits the value.
|
| @@ -1178,7 +1176,7 @@ static bool LookupForWrite(Handle<JSObject> receiver,
|
| // Ensure the instance and its map were migrated before trying to update the
|
| // transition target.
|
| ASSERT(!receiver->map()->is_deprecated());
|
| - if (!value->FitsRepresentation(target_details.representation())) {
|
| + if (!lookup->CanHoldValue(value)) {
|
| Handle<Map> target(lookup->GetTransitionTarget());
|
| Map::GeneralizeRepresentation(
|
| target, target->LastAdded(),
|
| @@ -1327,93 +1325,94 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
| Handle<JSObject> holder(lookup->holder());
|
| // Handlers do not use strict mode.
|
| StoreStubCompiler compiler(isolate(), SLOPPY, kind());
|
| - switch (lookup->type()) {
|
| - case FIELD:
|
| - return compiler.CompileStoreField(receiver, lookup, name);
|
| - case TRANSITION: {
|
| - // Explicitly pass in the receiver map since LookupForWrite may have
|
| - // stored something else than the receiver in the holder.
|
| - Handle<Map> transition(lookup->GetTransitionTarget());
|
| - PropertyDetails details = transition->GetLastDescriptorDetails();
|
| -
|
| - if (details.type() == CALLBACKS || details.attributes() != NONE) break;
|
| + if (lookup->IsTransition()) {
|
| + // Explicitly pass in the receiver map since LookupForWrite may have
|
| + // stored something else than the receiver in the holder.
|
| + Handle<Map> transition(lookup->GetTransitionTarget());
|
| + PropertyDetails details = lookup->GetPropertyDetails();
|
|
|
| + if (details.type() != CALLBACKS && details.attributes() == NONE) {
|
| return compiler.CompileStoreTransition(
|
| receiver, lookup, transition, name);
|
| }
|
| - case NORMAL:
|
| - if (kind() == Code::KEYED_STORE_IC) break;
|
| - if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) {
|
| - // The stub generated for the global object picks the value directly
|
| - // from the property cell. So the property must be directly on the
|
| - // global object.
|
| - Handle<GlobalObject> global = receiver->IsJSGlobalProxy()
|
| - ? handle(GlobalObject::cast(receiver->GetPrototype()))
|
| - : Handle<GlobalObject>::cast(receiver);
|
| - Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate());
|
| - Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
|
| - StoreGlobalStub stub(
|
| - union_type->IsConstant(), receiver->IsJSGlobalProxy());
|
| - Handle<Code> code = stub.GetCodeCopyFromTemplate(
|
| - isolate(), global, cell);
|
| - // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
|
| - HeapObject::UpdateMapCodeCache(receiver, name, code);
|
| - return code;
|
| - }
|
| - ASSERT(holder.is_identical_to(receiver));
|
| - return isolate()->builtins()->StoreIC_Normal();
|
| - case CALLBACKS: {
|
| - Handle<Object> callback(lookup->GetCallbackObject(), isolate());
|
| - if (callback->IsExecutableAccessorInfo()) {
|
| - Handle<ExecutableAccessorInfo> info =
|
| - Handle<ExecutableAccessorInfo>::cast(callback);
|
| - if (v8::ToCData<Address>(info->setter()) == 0) break;
|
| - if (!holder->HasFastProperties()) break;
|
| - if (!info->IsCompatibleReceiver(*receiver)) break;
|
| - return compiler.CompileStoreCallback(receiver, holder, name, info);
|
| - } else if (callback->IsAccessorPair()) {
|
| - Handle<Object> setter(
|
| - Handle<AccessorPair>::cast(callback)->setter(), isolate());
|
| - if (!setter->IsJSFunction()) break;
|
| - if (holder->IsGlobalObject()) break;
|
| - if (!holder->HasFastProperties()) break;
|
| - Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
|
| - CallOptimization call_optimization(function);
|
| - if (call_optimization.is_simple_api_call() &&
|
| - call_optimization.IsCompatibleReceiver(receiver, holder)) {
|
| - return compiler.CompileStoreCallback(
|
| - receiver, holder, name, call_optimization);
|
| + } else {
|
| + switch (lookup->type()) {
|
| + case FIELD:
|
| + return compiler.CompileStoreField(receiver, lookup, name);
|
| + case NORMAL:
|
| + if (kind() == Code::KEYED_STORE_IC) break;
|
| + if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) {
|
| + // The stub generated for the global object picks the value directly
|
| + // from the property cell. So the property must be directly on the
|
| + // global object.
|
| + Handle<GlobalObject> global = receiver->IsJSGlobalProxy()
|
| + ? handle(GlobalObject::cast(receiver->GetPrototype()))
|
| + : Handle<GlobalObject>::cast(receiver);
|
| + Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate());
|
| + Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
|
| + StoreGlobalStub stub(
|
| + union_type->IsConstant(), receiver->IsJSGlobalProxy());
|
| + Handle<Code> code = stub.GetCodeCopyFromTemplate(
|
| + isolate(), global, cell);
|
| + // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
|
| + HeapObject::UpdateMapCodeCache(receiver, name, code);
|
| + return code;
|
| + }
|
| + ASSERT(holder.is_identical_to(receiver));
|
| + return isolate()->builtins()->StoreIC_Normal();
|
| + case CALLBACKS: {
|
| + Handle<Object> callback(lookup->GetCallbackObject(), isolate());
|
| + if (callback->IsExecutableAccessorInfo()) {
|
| + Handle<ExecutableAccessorInfo> info =
|
| + Handle<ExecutableAccessorInfo>::cast(callback);
|
| + if (v8::ToCData<Address>(info->setter()) == 0) break;
|
| + if (!holder->HasFastProperties()) break;
|
| + if (!info->IsCompatibleReceiver(*receiver)) break;
|
| + return compiler.CompileStoreCallback(receiver, holder, name, info);
|
| + } else if (callback->IsAccessorPair()) {
|
| + Handle<Object> setter(
|
| + Handle<AccessorPair>::cast(callback)->setter(), isolate());
|
| + if (!setter->IsJSFunction()) break;
|
| + if (holder->IsGlobalObject()) break;
|
| + if (!holder->HasFastProperties()) break;
|
| + Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
|
| + CallOptimization call_optimization(function);
|
| + if (call_optimization.is_simple_api_call() &&
|
| + call_optimization.IsCompatibleReceiver(receiver, holder)) {
|
| + return compiler.CompileStoreCallback(
|
| + receiver, holder, name, call_optimization);
|
| + }
|
| + return compiler.CompileStoreViaSetter(
|
| + receiver, holder, name, Handle<JSFunction>::cast(setter));
|
| + }
|
| + // TODO(dcarney): Handle correctly.
|
| + if (callback->IsDeclaredAccessorInfo()) break;
|
| + ASSERT(callback->IsForeign());
|
| +
|
| + // Use specialized code for setting the length of arrays with fast
|
| + // properties. Slow properties might indicate redefinition of the length
|
| + // property.
|
| + if (receiver->IsJSArray() &&
|
| + name->Equals(isolate()->heap()->length_string()) &&
|
| + Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
|
| + receiver->HasFastProperties()) {
|
| + return compiler.CompileStoreArrayLength(receiver, lookup, name);
|
| }
|
| - return compiler.CompileStoreViaSetter(
|
| - receiver, holder, name, Handle<JSFunction>::cast(setter));
|
| - }
|
| - // TODO(dcarney): Handle correctly.
|
| - if (callback->IsDeclaredAccessorInfo()) break;
|
| - ASSERT(callback->IsForeign());
|
|
|
| - // Use specialized code for setting the length of arrays with fast
|
| - // properties. Slow properties might indicate redefinition of the length
|
| - // property.
|
| - if (receiver->IsJSArray() &&
|
| - name->Equals(isolate()->heap()->length_string()) &&
|
| - Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
|
| - receiver->HasFastProperties()) {
|
| - return compiler.CompileStoreArrayLength(receiver, lookup, name);
|
| + // No IC support for old-style native accessors.
|
| + break;
|
| }
|
| -
|
| - // No IC support for old-style native accessors.
|
| - break;
|
| + case INTERCEPTOR:
|
| + if (kind() == Code::KEYED_STORE_IC) break;
|
| + ASSERT(HasInterceptorSetter(*holder));
|
| + return compiler.CompileStoreInterceptor(receiver, name);
|
| + case CONSTANT:
|
| + break;
|
| + case NONEXISTENT:
|
| + case HANDLER:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| - case INTERCEPTOR:
|
| - if (kind() == Code::KEYED_STORE_IC) break;
|
| - ASSERT(HasInterceptorSetter(*holder));
|
| - return compiler.CompileStoreInterceptor(receiver, name);
|
| - case CONSTANT:
|
| - break;
|
| - case NONEXISTENT:
|
| - case HANDLER:
|
| - UNREACHABLE();
|
| - break;
|
| }
|
| return slow_stub();
|
| }
|
|
|