| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index 65d3f659320948a2ea57a16bdc8630bcc2eafaa0..30117c9f7aa0c0ae090eca63566c957f81b16f67 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -963,39 +963,20 @@ MaybeObject* LoadIC::Load(State state,
|
| }
|
|
|
|
|
| -void LoadIC::UpdateCaches(LookupResult* lookup,
|
| - State state,
|
| - Handle<Object> object,
|
| - Handle<String> name) {
|
| - // Bail out if the result is not cacheable.
|
| - if (!lookup->IsCacheable()) return;
|
| -
|
| - // Loading properties from values is not common, so don't try to
|
| - // deal with non-JS objects here.
|
| - if (!object->IsJSObject()) return;
|
| -
|
| - if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
|
| -
|
| - Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| - Handle<Code> code;
|
| - if (state == UNINITIALIZED) {
|
| - // This is the first time we execute this inline cache.
|
| - // Set the target to the pre monomorphic stub to delay
|
| - // setting the monomorphic state.
|
| - code = pre_monomorphic_stub();
|
| - } else {
|
| - code = ComputeLoadMonomorphic(lookup, receiver, name);
|
| - if (code.is_null()) return;
|
| - }
|
| -
|
| - // Patch the call site depending on the state of the cache.
|
| +void IC::PatchCache(State state,
|
| + StrictModeFlag strict_mode,
|
| + Handle<JSObject> receiver,
|
| + Handle<String> name,
|
| + Handle<Code> code) {
|
| switch (state) {
|
| case UNINITIALIZED:
|
| case PREMONOMORPHIC:
|
| case MONOMORPHIC_PROTOTYPE_FAILURE:
|
| + case POLYMORPHIC:
|
| set_target(*code);
|
| break;
|
| case MONOMORPHIC:
|
| + // Only move to megamorphic if the target changes.
|
| if (target() != *code) {
|
| // We are transitioning from monomorphic to megamorphic case.
|
| // Place the current monomorphic stub and stub compiled for
|
| @@ -1005,25 +986,53 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
|
| UpdateMegamorphicCache(map, *name, target());
|
| }
|
| UpdateMegamorphicCache(receiver->map(), *name, *code);
|
| - set_target(*megamorphic_stub());
|
| + set_target((strict_mode == kStrictMode)
|
| + ? *megamorphic_stub_strict()
|
| + : *megamorphic_stub());
|
| }
|
| break;
|
| case MEGAMORPHIC:
|
| + // Update the stub cache.
|
| UpdateMegamorphicCache(receiver->map(), *name, *code);
|
| break;
|
| - case DEBUG_STUB:
|
| - break;
|
| - case POLYMORPHIC:
|
| case GENERIC:
|
| - UNREACHABLE();
|
| + case DEBUG_STUB:
|
| break;
|
| }
|
| +}
|
| +
|
| +
|
| +void LoadIC::UpdateCaches(LookupResult* lookup,
|
| + State state,
|
| + Handle<Object> object,
|
| + Handle<String> name) {
|
| + // Bail out if the result is not cacheable.
|
| + if (!lookup->IsCacheable()) return;
|
| +
|
| + // Loading properties from values is not common, so don't try to
|
| + // deal with non-JS objects here.
|
| + if (!object->IsJSObject()) return;
|
| +
|
| + if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
|
| +
|
| + Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| + Handle<Code> code;
|
| + if (state == UNINITIALIZED) {
|
| + // This is the first time we execute this inline cache.
|
| + // Set the target to the pre monomorphic stub to delay
|
| + // setting the monomorphic state.
|
| + code = pre_monomorphic_stub();
|
| + } else {
|
| + code = ComputeLoadMonomorphic(lookup, receiver, name);
|
| + if (code.is_null()) return;
|
| + }
|
|
|
| + PatchCache(state, kNonStrictMode, receiver, name, code);
|
| TRACE_IC("LoadIC", name, state, target());
|
| }
|
|
|
|
|
| -void LoadIC::UpdateMegamorphicCache(Map* map, String* name, Code* code) {
|
| +void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) {
|
| // Cache code holding map should be consistent with
|
| // GenerateMonomorphicCacheProbe.
|
| isolate()->stub_cache()->Set(name, map, code);
|
| @@ -1424,7 +1433,7 @@ MaybeObject* StoreIC::Store(State state,
|
| LookupResult lookup(isolate());
|
| if (LookupForWrite(receiver, name, &lookup)) {
|
| if (FLAG_use_ic) {
|
| - UpdateStoreCaches(&lookup, state, strict_mode, receiver, name, value);
|
| + UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
|
| }
|
| } else if (strict_mode == kStrictMode &&
|
| !(lookup.IsProperty() && lookup.IsReadOnly()) &&
|
| @@ -1438,12 +1447,12 @@ MaybeObject* StoreIC::Store(State state,
|
| }
|
|
|
|
|
| -void StoreIC::UpdateStoreCaches(LookupResult* lookup,
|
| - State state,
|
| - StrictModeFlag strict_mode,
|
| - Handle<JSObject> receiver,
|
| - Handle<String> name,
|
| - Handle<Object> value) {
|
| +void StoreIC::UpdateCaches(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());
|
| @@ -1451,22 +1460,25 @@ void StoreIC::UpdateStoreCaches(LookupResult* lookup,
|
| // These are not cacheable, so we never see such LookupResults here.
|
| ASSERT(!lookup->IsHandler());
|
|
|
| - // 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.
|
| - PropertyType type = lookup->type();
|
| + Handle<Code> code =
|
| + ComputeStoreMonomorphic(lookup, strict_mode, receiver, name);
|
| + if (code.is_null()) return;
|
|
|
| - // Compute the code stub for this store; used for rewriting to
|
| - // monomorphic state and making sure that the code stub is in the
|
| - // stub cache.
|
| + PatchCache(state, strict_mode, receiver, name, code);
|
| + TRACE_IC("StoreIC", name, state, target());
|
| +}
|
| +
|
| +
|
| +Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
|
| + StrictModeFlag strict_mode,
|
| + Handle<JSObject> receiver,
|
| + Handle<String> name) {
|
| Handle<JSObject> holder(lookup->holder());
|
| - Handle<Code> code;
|
| - switch (type) {
|
| + switch (lookup->type()) {
|
| case FIELD:
|
| - code = isolate()->stub_cache()->ComputeStoreField(
|
| + return isolate()->stub_cache()->ComputeStoreField(
|
| name, receiver, lookup->GetFieldIndex().field_index(),
|
| Handle<Map>::null(), strict_mode);
|
| - break;
|
| case NORMAL:
|
| if (receiver->IsGlobalObject()) {
|
| // The stub generated for the global object picks the value directly
|
| @@ -1474,44 +1486,39 @@ void StoreIC::UpdateStoreCaches(LookupResult* lookup,
|
| // global object.
|
| Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
|
| Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup));
|
| - code = isolate()->stub_cache()->ComputeStoreGlobal(
|
| + return isolate()->stub_cache()->ComputeStoreGlobal(
|
| name, global, cell, strict_mode);
|
| - } else {
|
| - if (!holder.is_identical_to(receiver)) return;
|
| - code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
|
| }
|
| - break;
|
| + if (!holder.is_identical_to(receiver)) break;
|
| + return isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
|
| case CALLBACKS: {
|
| Handle<Object> callback(lookup->GetCallbackObject());
|
| if (callback->IsAccessorInfo()) {
|
| Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback);
|
| - if (v8::ToCData<Address>(info->setter()) == 0) return;
|
| - if (!holder->HasFastProperties()) return;
|
| - if (!info->IsCompatibleReceiver(*receiver)) return;
|
| - code = isolate()->stub_cache()->ComputeStoreCallback(
|
| + 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);
|
| } else if (callback->IsAccessorPair()) {
|
| Handle<Object> setter(Handle<AccessorPair>::cast(callback)->setter());
|
| - if (!setter->IsJSFunction()) return;
|
| - if (holder->IsGlobalObject()) return;
|
| - if (!holder->HasFastProperties()) return;
|
| - code = isolate()->stub_cache()->ComputeStoreViaSetter(
|
| + if (!setter->IsJSFunction()) break;
|
| + if (holder->IsGlobalObject()) break;
|
| + if (!holder->HasFastProperties()) break;
|
| + return isolate()->stub_cache()->ComputeStoreViaSetter(
|
| name, receiver, holder, Handle<JSFunction>::cast(setter),
|
| strict_mode);
|
| - } else {
|
| - ASSERT(callback->IsForeign());
|
| - // No IC support for old-style native accessors.
|
| - return;
|
| }
|
| + ASSERT(callback->IsForeign());
|
| + // No IC support for old-style native accessors.
|
| break;
|
| }
|
| case INTERCEPTOR:
|
| ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
|
| - code = isolate()->stub_cache()->ComputeStoreInterceptor(
|
| + return isolate()->stub_cache()->ComputeStoreInterceptor(
|
| name, receiver, strict_mode);
|
| - break;
|
| case CONSTANT_FUNCTION:
|
| - return;
|
| + break;
|
| case TRANSITION: {
|
| Handle<Map> transition(lookup->GetTransitionTarget());
|
| int descriptor = transition->LastAdded();
|
| @@ -1519,56 +1526,18 @@ void StoreIC::UpdateStoreCaches(LookupResult* lookup,
|
| DescriptorArray* target_descriptors = transition->instance_descriptors();
|
| PropertyDetails details = target_descriptors->GetDetails(descriptor);
|
|
|
| - if (details.type() != FIELD || details.attributes() != NONE) return;
|
| + if (details.type() != FIELD || details.attributes() != NONE) break;
|
|
|
| int field_index = target_descriptors->GetFieldIndex(descriptor);
|
| - code = isolate()->stub_cache()->ComputeStoreField(
|
| + return isolate()->stub_cache()->ComputeStoreField(
|
| name, receiver, field_index, transition, strict_mode);
|
| -
|
| - break;
|
| }
|
| case NONEXISTENT:
|
| case HANDLER:
|
| UNREACHABLE();
|
| - return;
|
| - }
|
| -
|
| - // Patch the call site depending on the state of the cache.
|
| - switch (state) {
|
| - case UNINITIALIZED:
|
| - case PREMONOMORPHIC:
|
| - case MONOMORPHIC_PROTOTYPE_FAILURE:
|
| - set_target(*code);
|
| - break;
|
| - case MONOMORPHIC:
|
| - // Only move to megamorphic if the target changes.
|
| - if (target() != *code) {
|
| - // We are transitioning from monomorphic to megamorphic case.
|
| - // Place the current monomorphic stub and stub compiled for
|
| - // the receiver into stub cache.
|
| - Map* map = target()->FindFirstMap();
|
| - if (map != NULL) {
|
| - isolate()->stub_cache()->Set(*name, map, target());
|
| - }
|
| - isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| - set_target((strict_mode == kStrictMode)
|
| - ? *megamorphic_stub_strict()
|
| - : *megamorphic_stub());
|
| - }
|
| - break;
|
| - case MEGAMORPHIC:
|
| - // Update the stub cache.
|
| - isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| - break;
|
| - case DEBUG_STUB:
|
| - break;
|
| - case POLYMORPHIC:
|
| - case GENERIC:
|
| - UNREACHABLE();
|
| break;
|
| }
|
| -
|
| - TRACE_IC("StoreIC", name, state, target());
|
| + return Handle<Code>::null();
|
| }
|
|
|
|
|
| @@ -1804,35 +1773,18 @@ MaybeObject* KeyedStoreIC::Store(State state,
|
| }
|
|
|
|
|
| -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());
|
| -
|
| - // These are not cacheable, so we never see such LookupResults here.
|
| - ASSERT(!lookup->IsHandler());
|
| -
|
| +Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
|
| + StrictModeFlag strict_mode,
|
| + Handle<JSObject> receiver,
|
| + Handle<String> name) {
|
| // 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.
|
| - PropertyType type = lookup->type();
|
| -
|
| - // Compute the code stub for this store; used for rewriting to
|
| - // monomorphic state and making sure that the code stub is in the
|
| - // stub cache.
|
| - Handle<Code> code;
|
| -
|
| - switch (type) {
|
| + switch (lookup->type()) {
|
| case FIELD:
|
| - code = isolate()->stub_cache()->ComputeKeyedStoreField(
|
| + return isolate()->stub_cache()->ComputeKeyedStoreField(
|
| name, receiver, lookup->GetFieldIndex().field_index(),
|
| Handle<Map>::null(), strict_mode);
|
| - break;
|
| case TRANSITION: {
|
| Handle<Map> transition(lookup->GetTransitionTarget());
|
| int descriptor = transition->LastAdded();
|
| @@ -1842,9 +1794,8 @@ void KeyedStoreIC::UpdateStoreCaches(LookupResult* lookup,
|
|
|
| if (details.type() == FIELD && details.attributes() == NONE) {
|
| int field_index = target_descriptors->GetFieldIndex(descriptor);
|
| - code = isolate()->stub_cache()->ComputeKeyedStoreField(
|
| + return isolate()->stub_cache()->ComputeKeyedStoreField(
|
| name, receiver, field_index, transition, strict_mode);
|
| - break;
|
| }
|
| // fall through.
|
| }
|
| @@ -1854,43 +1805,15 @@ void KeyedStoreIC::UpdateStoreCaches(LookupResult* lookup,
|
| case INTERCEPTOR:
|
| // Always rewrite to the generic case so that we do not
|
| // repeatedly try to rewrite.
|
| - code = (strict_mode == kStrictMode)
|
| + return (strict_mode == kStrictMode)
|
| ? generic_stub_strict()
|
| : generic_stub();
|
| - break;
|
| case HANDLER:
|
| case NONEXISTENT:
|
| UNREACHABLE();
|
| - return;
|
| - }
|
| -
|
| - ASSERT(!code.is_null());
|
| -
|
| - // Patch the call site depending on the state of the cache.
|
| - switch (state) {
|
| - case UNINITIALIZED:
|
| - case PREMONOMORPHIC:
|
| - case POLYMORPHIC:
|
| - set_target(*code);
|
| - break;
|
| - case MONOMORPHIC:
|
| - // Only move to megamorphic if the target changes.
|
| - if (target() != *code) {
|
| - set_target((strict_mode == kStrictMode)
|
| - ? *megamorphic_stub_strict()
|
| - : *megamorphic_stub());
|
| - }
|
| - break;
|
| - case MEGAMORPHIC:
|
| - case GENERIC:
|
| - case DEBUG_STUB:
|
| - break;
|
| - case MONOMORPHIC_PROTOTYPE_FAILURE:
|
| - UNREACHABLE();
|
| break;
|
| }
|
| -
|
| - TRACE_IC("KeyedStoreIC", name, state, target());
|
| + return Handle<Code>::null();
|
| }
|
|
|
|
|
|
|