| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index be362d2a4b90967be70fa4d46939123a37006be0..4bff543a733305ec33c966e5a890195013e538c5 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -117,7 +117,9 @@ void IC::TraceIC(const char* type,
|
| #define TRACE_IC(type, name) \
|
| ASSERT((TraceIC(type, name), true))
|
|
|
| -IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
|
| +IC::IC(FrameDepth depth, Isolate* isolate)
|
| + : isolate_(isolate),
|
| + target_set_(false) {
|
| // To improve the performance of the (much used) IC code, we unfold a few
|
| // levels of the stack frame iteration code. This yields a ~35% speedup when
|
| // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
|
| @@ -300,7 +302,8 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
|
| break;
|
| }
|
|
|
| - Map* map = IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map();
|
| + Handle<Map> map(
|
| + IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map());
|
|
|
| // Decide whether the inline cache failed because of changes to the
|
| // receiver itself or changes to one of its prototypes.
|
| @@ -314,13 +317,7 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
|
| if (index >= 0) {
|
| map->RemoveFromCodeCache(*name, *target(), index);
|
| // Handlers are stored in addition to the ICs on the map. Remove those, too.
|
| - Code* handler = target()->FindFirstHandler();
|
| - if (handler != NULL) {
|
| - index = map->IndexInCodeCache(*name, handler);
|
| - if (index >= 0) {
|
| - map->RemoveFromCodeCache(*name, handler, index);
|
| - }
|
| - }
|
| + TryRemoveInvalidHandlers(map, name);
|
| return true;
|
| }
|
|
|
| @@ -334,7 +331,7 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
|
| // the map cannot be deprecated and the stub invalidated.
|
| if (cache_holder == OWN_MAP) {
|
| Map* old_map = target()->FindFirstMap();
|
| - if (old_map == map) return true;
|
| + if (old_map == *map) return true;
|
| if (old_map != NULL) {
|
| if (old_map->is_deprecated()) return true;
|
| if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
|
| @@ -357,8 +354,30 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
|
| }
|
|
|
|
|
| +void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) {
|
| + CodeHandleList handlers;
|
| + target()->FindHandlers(&handlers);
|
| + for (int i = 0; i < handlers.length(); i++) {
|
| + Handle<Code> handler = handlers.at(i);
|
| + int index = map->IndexInCodeCache(*name, *handler);
|
| + if (index >= 0) {
|
| + map->RemoveFromCodeCache(*name, *handler, index);
|
| + return;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
|
| - if (state() != MONOMORPHIC || !name->IsString()) return;
|
| + if (!name->IsString()) return;
|
| + if (state() != MONOMORPHIC) {
|
| + if (state() == POLYMORPHIC && receiver->IsHeapObject()) {
|
| + TryRemoveInvalidHandlers(
|
| + handle(Handle<HeapObject>::cast(receiver)->map()),
|
| + Handle<String>::cast(name));
|
| + }
|
| + return;
|
| + }
|
| if (receiver->IsUndefined() || receiver->IsNull()) return;
|
|
|
| // Remove the target from the code cache if it became invalid
|
| @@ -1088,6 +1107,18 @@ void IC::PatchCache(Handle<HeapObject> receiver,
|
| }
|
|
|
|
|
| +Handle<Code> LoadIC::SimpleFieldLoad(int offset,
|
| + bool inobject,
|
| + Representation representation) {
|
| + if (kind() == Code::LOAD_IC) {
|
| + LoadFieldStub stub(inobject, offset, representation);
|
| + return stub.GetCode(isolate());
|
| + } else {
|
| + KeyedLoadFieldStub stub(inobject, offset, representation);
|
| + return stub.GetCode(isolate());
|
| + }
|
| +}
|
| +
|
| void LoadIC::UpdateCaches(LookupResult* lookup,
|
| Handle<Object> object,
|
| Handle<String> name) {
|
| @@ -1109,20 +1140,18 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
|
| } else if (object->IsString() &&
|
| name->Equals(isolate()->heap()->length_string())) {
|
| int length_index = String::kLengthOffset / kPointerSize;
|
| - if (target()->is_load_stub()) {
|
| - LoadFieldStub stub(true, length_index, Representation::Tagged());
|
| - code = stub.GetCode(isolate());
|
| - } else {
|
| - KeyedLoadFieldStub stub(true, length_index, Representation::Tagged());
|
| - code = stub.GetCode(isolate());
|
| - }
|
| + code = SimpleFieldLoad(length_index);
|
| } else if (!object->IsJSObject()) {
|
| // TODO(jkummerow): It would be nice to support non-JSObjects in
|
| // ComputeLoadHandler, then we wouldn't need to go generic here.
|
| code = slow_stub();
|
| + } else if (!lookup->IsProperty()) {
|
| + code = kind() == Code::LOAD_IC
|
| + ? isolate()->stub_cache()->ComputeLoadNonexistent(
|
| + name, Handle<JSObject>::cast(receiver))
|
| + : slow_stub();
|
| } else {
|
| - code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name);
|
| - if (code.is_null()) code = slow_stub();
|
| + code = ComputeHandler(lookup, Handle<JSObject>::cast(receiver), name);
|
| }
|
|
|
| PatchCache(receiver, name, code);
|
| @@ -1137,34 +1166,56 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
|
| }
|
|
|
|
|
| -Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
|
| - Handle<JSObject> receiver,
|
| - Handle<String> name) {
|
| - if (!lookup->IsProperty()) {
|
| - // Nonexistent property. The result is undefined.
|
| - return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver);
|
| +Handle<Code> IC::ComputeHandler(LookupResult* lookup,
|
| + Handle<JSObject> receiver,
|
| + Handle<String> name,
|
| + Handle<Object> value) {
|
| + Handle<Code> code = isolate()->stub_cache()->FindHandler(
|
| + name, receiver, kind());
|
| + if (!code.is_null()) return code;
|
| +
|
| + code = CompileHandler(lookup, receiver, name, value);
|
| +
|
| + if (code->is_handler() && code->type() != Code::NORMAL) {
|
| + HeapObject::UpdateMapCodeCache(receiver, name, code);
|
| }
|
|
|
| - // Compute monomorphic stub.
|
| + return code;
|
| +}
|
| +
|
| +
|
| +Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
|
| + Handle<JSObject> receiver,
|
| + Handle<String> name,
|
| + Handle<Object> unused) {
|
| Handle<JSObject> holder(lookup->holder());
|
| + LoadStubCompiler compiler(isolate(), kind());
|
| +
|
| switch (lookup->type()) {
|
| - case FIELD:
|
| - return isolate()->stub_cache()->ComputeLoadField(
|
| - name, receiver, holder,
|
| - lookup->GetFieldIndex(), lookup->representation());
|
| + case FIELD: {
|
| + PropertyIndex field = lookup->GetFieldIndex();
|
| + if (receiver.is_identical_to(holder)) {
|
| + return SimpleFieldLoad(field.translate(holder),
|
| + field.is_inobject(holder),
|
| + lookup->representation());
|
| + }
|
| + return compiler.CompileLoadField(
|
| + receiver, holder, name, field, lookup->representation());
|
| + }
|
| case CONSTANT: {
|
| Handle<Object> constant(lookup->GetConstant(), isolate());
|
| // TODO(2803): Don't compute a stub for cons strings because they cannot
|
| // be embedded into code.
|
| - if (constant->IsConsString()) return Handle<Code>::null();
|
| - return isolate()->stub_cache()->ComputeLoadConstant(
|
| - name, receiver, holder, constant);
|
| + if (constant->IsConsString()) break;
|
| + return compiler.CompileLoadConstant(receiver, holder, name, constant);
|
| }
|
| case NORMAL:
|
| + if (kind() != Code::LOAD_IC) break;
|
| if (holder->IsGlobalObject()) {
|
| Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
|
| Handle<PropertyCell> cell(
|
| global->GetPropertyCell(lookup), isolate());
|
| + // TODO(verwaest): Turn into a handler.
|
| return isolate()->stub_cache()->ComputeLoadGlobal(
|
| name, receiver, global, cell, lookup->IsDontDelete());
|
| }
|
| @@ -1173,18 +1224,16 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
|
| // property must be found in the receiver for the stub to be
|
| // applicable.
|
| if (!holder.is_identical_to(receiver)) break;
|
| - return isolate()->stub_cache()->ComputeLoadNormal(name, receiver);
|
| + return isolate()->builtins()->LoadIC_Normal();
|
| case CALLBACKS: {
|
| - {
|
| - // Use simple field loads for some well-known callback properties.
|
| - int object_offset;
|
| - Handle<Map> map(receiver->map());
|
| - if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
|
| - PropertyIndex index =
|
| - PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
|
| - return isolate()->stub_cache()->ComputeLoadField(
|
| - name, receiver, receiver, index, Representation::Tagged());
|
| - }
|
| + // Use simple field loads for some well-known callback properties.
|
| + int object_offset;
|
| + Handle<Map> map(receiver->map());
|
| + if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
|
| + PropertyIndex index =
|
| + PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
|
| + return compiler.CompileLoadField(
|
| + receiver, receiver, name, index, Representation::Tagged());
|
| }
|
|
|
| Handle<Object> callback(lookup->GetCallbackObject(), isolate());
|
| @@ -1193,8 +1242,7 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
|
| Handle<ExecutableAccessorInfo>::cast(callback);
|
| if (v8::ToCData<Address>(info->getter()) == 0) break;
|
| if (!info->IsCompatibleReceiver(*receiver)) break;
|
| - return isolate()->stub_cache()->ComputeLoadCallback(
|
| - name, receiver, holder, info);
|
| + return compiler.CompileLoadCallback(receiver, holder, name, info);
|
| } else if (callback->IsAccessorPair()) {
|
| Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
|
| isolate());
|
| @@ -1205,11 +1253,10 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
|
| CallOptimization call_optimization(function);
|
| if (call_optimization.is_simple_api_call() &&
|
| call_optimization.IsCompatibleReceiver(*receiver)) {
|
| - return isolate()->stub_cache()->ComputeLoadCallback(
|
| - name, receiver, holder, call_optimization);
|
| + return compiler.CompileLoadCallback(
|
| + receiver, holder, name, call_optimization);
|
| }
|
| - return isolate()->stub_cache()->ComputeLoadViaGetter(
|
| - name, receiver, holder, function);
|
| + return compiler.CompileLoadViaGetter(receiver, holder, name, function);
|
| }
|
| // TODO(dcarney): Handle correctly.
|
| if (callback->IsDeclaredAccessorInfo()) break;
|
| @@ -1219,12 +1266,12 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
|
| }
|
| case INTERCEPTOR:
|
| ASSERT(HasInterceptorGetter(*holder));
|
| - return isolate()->stub_cache()->ComputeLoadInterceptor(
|
| - name, receiver, holder);
|
| + return compiler.CompileLoadInterceptor(receiver, holder, name);
|
| default:
|
| break;
|
| }
|
| - return Handle<Code>::null();
|
| +
|
| + return slow_stub();
|
| }
|
|
|
|
|
| @@ -1318,105 +1365,50 @@ MaybeObject* KeyedLoadIC::Load(Handle<Object> object,
|
| return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
|
| }
|
|
|
| + MaybeObject* maybe_object = NULL;
|
| + Handle<Code> stub = generic_stub();
|
| +
|
| // Check for values that can be converted into an internalized string directly
|
| // or is representable as a smi.
|
| key = TryConvertKey(key, isolate());
|
|
|
| if (key->IsInternalizedString()) {
|
| - return LoadIC::Load(object, Handle<String>::cast(key));
|
| - }
|
| -
|
| - if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
|
| + maybe_object = LoadIC::Load(object, Handle<String>::cast(key));
|
| + if (maybe_object->IsFailure()) return maybe_object;
|
| + } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
|
| ASSERT(!object->IsJSGlobalProxy());
|
| - Handle<Code> stub = generic_stub();
|
| - if (miss_mode == MISS_FORCE_GENERIC) {
|
| - TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "force generic");
|
| - } else if (object->IsString() && key->IsNumber()) {
|
| - if (state() == UNINITIALIZED) stub = string_stub();
|
| - } else if (object->IsJSObject()) {
|
| - Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| - if (receiver->elements()->map() ==
|
| - isolate()->heap()->non_strict_arguments_elements_map()) {
|
| - stub = non_strict_arguments_stub();
|
| - } else if (receiver->HasIndexedInterceptor()) {
|
| - stub = indexed_interceptor_stub();
|
| - } else if (!key->ToSmi()->IsFailure() &&
|
| - (!target().is_identical_to(non_strict_arguments_stub()))) {
|
| - stub = LoadElementStub(receiver);
|
| + if (miss_mode != MISS_FORCE_GENERIC) {
|
| + if (object->IsString() && key->IsNumber()) {
|
| + if (state() == UNINITIALIZED) stub = string_stub();
|
| + } else if (object->IsJSObject()) {
|
| + Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| + if (receiver->elements()->map() ==
|
| + isolate()->heap()->non_strict_arguments_elements_map()) {
|
| + stub = non_strict_arguments_stub();
|
| + } else if (receiver->HasIndexedInterceptor()) {
|
| + stub = indexed_interceptor_stub();
|
| + } else if (!key->ToSmi()->IsFailure() &&
|
| + (!target().is_identical_to(non_strict_arguments_stub()))) {
|
| + stub = LoadElementStub(receiver);
|
| + }
|
| }
|
| }
|
| + }
|
|
|
| + if (!is_target_set()) {
|
| + if (*stub == *generic_stub()) {
|
| + TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
|
| + }
|
| ASSERT(!stub.is_null());
|
| set_target(*stub);
|
| TRACE_IC("LoadIC", key);
|
| }
|
|
|
| -
|
| + if (maybe_object != NULL) return maybe_object;
|
| return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
|
| }
|
|
|
|
|
| -Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup,
|
| - Handle<JSObject> receiver,
|
| - Handle<String> name) {
|
| - // Bail out if we didn't find a result.
|
| - if (!lookup->IsProperty()) return Handle<Code>::null();
|
| -
|
| - // Compute a monomorphic stub.
|
| - Handle<JSObject> holder(lookup->holder(), isolate());
|
| - switch (lookup->type()) {
|
| - case FIELD:
|
| - return isolate()->stub_cache()->ComputeKeyedLoadField(
|
| - name, receiver, holder,
|
| - lookup->GetFieldIndex(), lookup->representation());
|
| - case CONSTANT: {
|
| - Handle<Object> constant(lookup->GetConstant(), isolate());
|
| - // TODO(2803): Don't compute a stub for cons strings because they cannot
|
| - // be embedded into code.
|
| - if (constant->IsConsString()) return Handle<Code>::null();
|
| - return isolate()->stub_cache()->ComputeKeyedLoadConstant(
|
| - name, receiver, holder, constant);
|
| - }
|
| - case CALLBACKS: {
|
| - Handle<Object> callback_object(lookup->GetCallbackObject(), isolate());
|
| - // TODO(dcarney): Handle DeclaredAccessorInfo correctly.
|
| - if (callback_object->IsExecutableAccessorInfo()) {
|
| - Handle<ExecutableAccessorInfo> callback =
|
| - Handle<ExecutableAccessorInfo>::cast(callback_object);
|
| - if (v8::ToCData<Address>(callback->getter()) == 0) break;
|
| - if (!callback->IsCompatibleReceiver(*receiver)) break;
|
| - return isolate()->stub_cache()->ComputeKeyedLoadCallback(
|
| - name, receiver, holder, callback);
|
| - } else if (callback_object->IsAccessorPair()) {
|
| - Handle<Object> getter(
|
| - Handle<AccessorPair>::cast(callback_object)->getter(),
|
| - isolate());
|
| - if (!getter->IsJSFunction()) break;
|
| - if (holder->IsGlobalObject()) break;
|
| - if (!holder->HasFastProperties()) break;
|
| - Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
|
| - CallOptimization call_optimization(function);
|
| - if (call_optimization.is_simple_api_call() &&
|
| - call_optimization.IsCompatibleReceiver(*receiver)) {
|
| - return isolate()->stub_cache()->ComputeKeyedLoadCallback(
|
| - name, receiver, holder, call_optimization);
|
| - }
|
| - }
|
| - break;
|
| - }
|
| - case INTERCEPTOR:
|
| - ASSERT(HasInterceptorGetter(lookup->holder()));
|
| - return isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
|
| - name, receiver, holder);
|
| - default:
|
| - // Always rewrite to the generic case so that we do not
|
| - // repeatedly try to rewrite.
|
| - return generic_stub();
|
| - }
|
| - return Handle<Code>::null();
|
| -}
|
| -
|
| -
|
| static bool LookupForWrite(Handle<JSObject> receiver,
|
| Handle<String> name,
|
| Handle<Object> value,
|
| @@ -1602,27 +1594,39 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
| // These are not cacheable, so we never see such LookupResults here.
|
| ASSERT(!lookup->IsHandler());
|
|
|
| - Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value);
|
| - if (code.is_null()) {
|
| - set_target(*generic_stub());
|
| - return;
|
| - }
|
| + Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
|
|
|
| PatchCache(receiver, name, code);
|
| TRACE_IC("StoreIC", name);
|
| }
|
|
|
|
|
| -Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
|
| - Handle<JSObject> receiver,
|
| - Handle<String> name,
|
| - Handle<Object> value) {
|
| +Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
| + Handle<JSObject> receiver,
|
| + Handle<String> name,
|
| + Handle<Object> value) {
|
| Handle<JSObject> holder(lookup->holder());
|
| + StoreStubCompiler compiler(isolate(), strict_mode(), kind());
|
| switch (lookup->type()) {
|
| case FIELD:
|
| - return isolate()->stub_cache()->ComputeStoreField(
|
| - name, receiver, lookup, strict_mode());
|
| + 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(receiver->map()), isolate());
|
| + int descriptor = transition->LastAdded();
|
| +
|
| + DescriptorArray* target_descriptors = transition->instance_descriptors();
|
| + PropertyDetails details = target_descriptors->GetDetails(descriptor);
|
| +
|
| + if (details.type() == CALLBACKS || details.attributes() != NONE) break;
|
| +
|
| + return compiler.CompileStoreTransition(
|
| + receiver, lookup, transition, name);
|
| + }
|
| case NORMAL:
|
| + if (kind() == Code::KEYED_STORE_IC) break;
|
| if (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
|
| @@ -1630,12 +1634,16 @@ Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
|
| Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
|
| Handle<PropertyCell> cell(
|
| global->GetPropertyCell(lookup), isolate());
|
| + // TODO(verwaest): Turn into a handler.
|
| return isolate()->stub_cache()->ComputeStoreGlobal(
|
| name, global, cell, value, strict_mode());
|
| }
|
| ASSERT(holder.is_identical_to(receiver));
|
| - return isolate()->stub_cache()->ComputeStoreNormal(strict_mode());
|
| + return strict_mode() == kStrictMode
|
| + ? isolate()->builtins()->StoreIC_Normal_Strict()
|
| + : isolate()->builtins()->StoreIC_Normal();
|
| case CALLBACKS: {
|
| + if (kind() == Code::KEYED_STORE_IC) break;
|
| Handle<Object> callback(lookup->GetCallbackObject(), isolate());
|
| if (callback->IsExecutableAccessorInfo()) {
|
| Handle<ExecutableAccessorInfo> info =
|
| @@ -1643,8 +1651,7 @@ Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
|
| if (v8::ToCData<Address>(info->setter()) == 0) break;
|
| if (!holder->HasFastProperties()) break;
|
| if (!info->IsCompatibleReceiver(*receiver)) break;
|
| - return isolate()->stub_cache()->ComputeStoreCallback(
|
| - name, receiver, holder, info, strict_mode());
|
| + return compiler.CompileStoreCallback(receiver, holder, name, info);
|
| } else if (callback->IsAccessorPair()) {
|
| Handle<Object> setter(
|
| Handle<AccessorPair>::cast(callback)->setter(), isolate());
|
| @@ -1655,12 +1662,11 @@ Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
|
| CallOptimization call_optimization(function);
|
| if (call_optimization.is_simple_api_call() &&
|
| call_optimization.IsCompatibleReceiver(*receiver)) {
|
| - return isolate()->stub_cache()->ComputeStoreCallback(
|
| - name, receiver, holder, call_optimization, strict_mode());
|
| + return compiler.CompileStoreCallback(
|
| + receiver, holder, name, call_optimization);
|
| }
|
| - return isolate()->stub_cache()->ComputeStoreViaSetter(
|
| - name, receiver, holder, Handle<JSFunction>::cast(setter),
|
| - strict_mode());
|
| + return compiler.CompileStoreViaSetter(
|
| + receiver, holder, name, Handle<JSFunction>::cast(setter));
|
| }
|
| // TODO(dcarney): Handle correctly.
|
| if (callback->IsDeclaredAccessorInfo()) break;
|
| @@ -1669,32 +1675,17 @@ Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
|
| break;
|
| }
|
| case INTERCEPTOR:
|
| + if (kind() == Code::KEYED_STORE_IC) break;
|
| ASSERT(HasInterceptorSetter(*receiver));
|
| - return isolate()->stub_cache()->ComputeStoreInterceptor(
|
| - name, receiver, strict_mode());
|
| + return compiler.CompileStoreInterceptor(receiver, name);
|
| case CONSTANT:
|
| break;
|
| - 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(receiver->map()), isolate());
|
| - int descriptor = transition->LastAdded();
|
| -
|
| - DescriptorArray* target_descriptors = transition->instance_descriptors();
|
| - PropertyDetails details = target_descriptors->GetDetails(descriptor);
|
| -
|
| - if (details.type() == CALLBACKS || details.attributes() != NONE) break;
|
| -
|
| - return isolate()->stub_cache()->ComputeStoreTransition(
|
| - name, receiver, lookup, transition, strict_mode());
|
| - }
|
| case NONEXISTENT:
|
| case HANDLER:
|
| UNREACHABLE();
|
| break;
|
| }
|
| - return Handle<Code>::null();
|
| + return slow_stub();
|
| }
|
|
|
|
|
| @@ -1953,101 +1944,63 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
|
| // or is representable as a smi.
|
| key = TryConvertKey(key, isolate());
|
|
|
| - if (key->IsInternalizedString()) {
|
| - return StoreIC::Store(object,
|
| - Handle<String>::cast(key),
|
| - value,
|
| - JSReceiver::MAY_BE_STORE_FROM_KEYED);
|
| - }
|
| + MaybeObject* maybe_object = NULL;
|
| + Handle<Code> stub = generic_stub();
|
|
|
| - bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
|
| - !(FLAG_harmony_observation && object->IsJSObject() &&
|
| - JSObject::cast(*object)->map()->is_observed());
|
| - if (use_ic && !object->IsSmi()) {
|
| - // Don't use ICs for maps of the objects in Array's prototype chain. We
|
| - // expect to be able to trap element sets to objects with those maps in the
|
| - // runtime to enable optimization of element hole access.
|
| - Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
|
| - if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false;
|
| - }
|
| -
|
| - if (use_ic) {
|
| - ASSERT(!object->IsJSGlobalProxy());
|
| + if (key->IsInternalizedString()) {
|
| + maybe_object = StoreIC::Store(object,
|
| + Handle<String>::cast(key),
|
| + value,
|
| + JSReceiver::MAY_BE_STORE_FROM_KEYED);
|
| + if (maybe_object->IsFailure()) return maybe_object;
|
| + } else {
|
| + bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
|
| + !(FLAG_harmony_observation && object->IsJSObject() &&
|
| + JSObject::cast(*object)->map()->is_observed());
|
| + if (use_ic && !object->IsSmi()) {
|
| + // Don't use ICs for maps of the objects in Array's prototype chain. We
|
| + // expect to be able to trap element sets to objects with those maps in
|
| + // the runtime to enable optimization of element hole access.
|
| + Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
|
| + if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false;
|
| + }
|
|
|
| - Handle<Code> stub = generic_stub();
|
| - if (miss_mode != MISS_FORCE_GENERIC) {
|
| - if (object->IsJSObject()) {
|
| - Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| - bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure();
|
| - if (receiver->elements()->map() ==
|
| - isolate()->heap()->non_strict_arguments_elements_map()) {
|
| - stub = non_strict_arguments_stub();
|
| - } else if (key_is_smi_like &&
|
| - (!target().is_identical_to(non_strict_arguments_stub()))) {
|
| - KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
|
| - stub = StoreElementStub(receiver, store_mode);
|
| - } else {
|
| - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number");
|
| + if (use_ic) {
|
| + ASSERT(!object->IsJSGlobalProxy());
|
| +
|
| + if (miss_mode != MISS_FORCE_GENERIC) {
|
| + if (object->IsJSObject()) {
|
| + Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| + bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure();
|
| + if (receiver->elements()->map() ==
|
| + isolate()->heap()->non_strict_arguments_elements_map()) {
|
| + stub = non_strict_arguments_stub();
|
| + } else if (key_is_smi_like &&
|
| + (!target().is_identical_to(non_strict_arguments_stub()))) {
|
| + KeyedAccessStoreMode store_mode =
|
| + GetStoreMode(receiver, key, value);
|
| + stub = StoreElementStub(receiver, store_mode);
|
| + }
|
| }
|
| - } else {
|
| - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object");
|
| }
|
| - } else {
|
| - TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic");
|
| + }
|
| + }
|
| +
|
| + if (!is_target_set()) {
|
| + if (*stub == *generic_stub()) {
|
| + TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
|
| }
|
| ASSERT(!stub.is_null());
|
| set_target(*stub);
|
| TRACE_IC("StoreIC", key);
|
| }
|
|
|
| + if (maybe_object) return maybe_object;
|
| return Runtime::SetObjectPropertyOrFail(
|
| isolate(), object , key, value, NONE, strict_mode());
|
| }
|
|
|
|
|
| -Handle<Code> KeyedStoreIC::ComputeStoreHandler(LookupResult* lookup,
|
| - Handle<JSObject> receiver,
|
| - Handle<String> name,
|
| - Handle<Object> value) {
|
| - // If the property has a non-field type allowing map transitions
|
| - // where there is extra room in the object, we leave the IC in its
|
| - // current state.
|
| - switch (lookup->type()) {
|
| - case FIELD:
|
| - return isolate()->stub_cache()->ComputeKeyedStoreField(
|
| - name, receiver, lookup, strict_mode());
|
| - 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(receiver->map()), isolate());
|
| - int descriptor = transition->LastAdded();
|
| -
|
| - DescriptorArray* target_descriptors = transition->instance_descriptors();
|
| - PropertyDetails details = target_descriptors->GetDetails(descriptor);
|
| -
|
| - if (details.type() != CALLBACKS && details.attributes() == NONE) {
|
| - return isolate()->stub_cache()->ComputeKeyedStoreTransition(
|
| - name, receiver, lookup, transition, strict_mode());
|
| - }
|
| - // fall through.
|
| - }
|
| - case NORMAL:
|
| - case CONSTANT:
|
| - case CALLBACKS:
|
| - case INTERCEPTOR:
|
| - // Always rewrite to the generic case so that we do not
|
| - // repeatedly try to rewrite.
|
| - return generic_stub();
|
| - case HANDLER:
|
| - case NONEXISTENT:
|
| - UNREACHABLE();
|
| - break;
|
| - }
|
| - return Handle<Code>::null();
|
| -}
|
| -
|
| -
|
| #undef TRACE_IC
|
|
|
|
|
|
|