Index: src/ic.cc |
diff --git a/src/ic.cc b/src/ic.cc |
index 49b33776cea839863b381ae3b4dbc5c485138c29..65d3f659320948a2ea57a16bdc8630bcc2eafaa0 100644 |
--- a/src/ic.cc |
+++ b/src/ic.cc |
@@ -941,7 +941,7 @@ MaybeObject* LoadIC::Load(State state, |
// Update inline cache and stub cache. |
if (FLAG_use_ic) { |
- UpdateLoadCaches(&lookup, state, object, name); |
+ UpdateCaches(&lookup, state, object, name); |
} |
PropertyAttributes attr; |
@@ -963,89 +963,29 @@ MaybeObject* LoadIC::Load(State state, |
} |
-void LoadIC::UpdateLoadCaches(LookupResult* lookup, |
- State state, |
- Handle<Object> object, |
- Handle<String> name) { |
+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; |
- Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
- // Compute the code stub for this load. |
+ 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 if (!lookup->IsProperty()) { |
- // Nonexistent property. The result is undefined. |
- code = isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); |
} else { |
- // Compute monomorphic stub. |
- Handle<JSObject> holder(lookup->holder()); |
- switch (lookup->type()) { |
- case FIELD: |
- code = isolate()->stub_cache()->ComputeLoadField( |
- name, receiver, holder, lookup->GetFieldIndex()); |
- break; |
- case CONSTANT_FUNCTION: { |
- Handle<JSFunction> constant(lookup->GetConstantFunction()); |
- code = isolate()->stub_cache()->ComputeLoadConstant( |
- name, receiver, holder, constant); |
- break; |
- } |
- case NORMAL: |
- if (holder->IsGlobalObject()) { |
- Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
- Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); |
- code = isolate()->stub_cache()->ComputeLoadGlobal( |
- name, receiver, global, cell, lookup->IsDontDelete()); |
- } else { |
- // There is only one shared stub for loading normalized |
- // properties. It does not traverse the prototype chain, so the |
- // property must be found in the receiver for the stub to be |
- // applicable. |
- if (!holder.is_identical_to(receiver)) return; |
- code = isolate()->stub_cache()->ComputeLoadNormal(); |
- } |
- break; |
- case CALLBACKS: { |
- Handle<Object> callback(lookup->GetCallbackObject()); |
- if (callback->IsAccessorInfo()) { |
- Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback); |
- if (v8::ToCData<Address>(info->getter()) == 0) return; |
- if (!info->IsCompatibleReceiver(*receiver)) return; |
- code = isolate()->stub_cache()->ComputeLoadCallback( |
- name, receiver, holder, info); |
- } else if (callback->IsAccessorPair()) { |
- Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter()); |
- if (!getter->IsJSFunction()) return; |
- if (holder->IsGlobalObject()) return; |
- if (!holder->HasFastProperties()) return; |
- code = isolate()->stub_cache()->ComputeLoadViaGetter( |
- name, receiver, holder, Handle<JSFunction>::cast(getter)); |
- } else { |
- ASSERT(callback->IsForeign()); |
- // No IC support for old-style native accessors. |
- return; |
- } |
- break; |
- } |
- case INTERCEPTOR: |
- ASSERT(HasInterceptorGetter(*holder)); |
- code = isolate()->stub_cache()->ComputeLoadInterceptor( |
- name, receiver, holder); |
- break; |
- default: |
- return; |
- } |
+ code = ComputeLoadMonomorphic(lookup, receiver, name); |
+ if (code.is_null()) return; |
} |
// Patch the call site depending on the state of the cache. |
@@ -1062,17 +1002,14 @@ void LoadIC::UpdateLoadCaches(LookupResult* lookup, |
// the receiver into stub cache. |
Map* map = target()->FindFirstMap(); |
if (map != NULL) { |
- isolate()->stub_cache()->Set(*name, map, target()); |
+ UpdateMegamorphicCache(map, *name, target()); |
} |
- isolate()->stub_cache()->Set(*name, receiver->map(), *code); |
- |
+ UpdateMegamorphicCache(receiver->map(), *name, *code); |
set_target(*megamorphic_stub()); |
} |
break; |
case MEGAMORPHIC: |
- // Cache code holding map should be consistent with |
- // GenerateMonomorphicCacheProbe. |
- isolate()->stub_cache()->Set(*name, receiver->map(), *code); |
+ UpdateMegamorphicCache(receiver->map(), *name, *code); |
break; |
case DEBUG_STUB: |
break; |
@@ -1086,6 +1023,76 @@ void LoadIC::UpdateLoadCaches(LookupResult* lookup, |
} |
+void LoadIC::UpdateMegamorphicCache(Map* map, String* name, Code* code) { |
+ // Cache code holding map should be consistent with |
+ // GenerateMonomorphicCacheProbe. |
+ isolate()->stub_cache()->Set(name, map, code); |
+} |
+ |
+ |
+Handle<Code> LoadIC::ComputeLoadMonomorphic(LookupResult* lookup, |
+ Handle<JSObject> receiver, |
+ Handle<String> name) { |
+ if (!lookup->IsProperty()) { |
+ // Nonexistent property. The result is undefined. |
+ return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); |
+ } |
+ |
+ // Compute monomorphic stub. |
+ Handle<JSObject> holder(lookup->holder()); |
+ switch (lookup->type()) { |
+ case FIELD: |
+ return isolate()->stub_cache()->ComputeLoadField( |
+ name, receiver, holder, lookup->GetFieldIndex()); |
+ case CONSTANT_FUNCTION: { |
+ Handle<JSFunction> constant(lookup->GetConstantFunction()); |
+ return isolate()->stub_cache()->ComputeLoadConstant( |
+ name, receiver, holder, constant); |
+ } |
+ case NORMAL: |
+ if (holder->IsGlobalObject()) { |
+ Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
+ Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); |
+ return isolate()->stub_cache()->ComputeLoadGlobal( |
+ name, receiver, global, cell, lookup->IsDontDelete()); |
+ } |
+ // There is only one shared stub for loading normalized |
+ // properties. It does not traverse the prototype chain, so the |
+ // 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(); |
+ case CALLBACKS: { |
+ Handle<Object> callback(lookup->GetCallbackObject()); |
+ if (callback->IsAccessorInfo()) { |
+ Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback); |
+ if (v8::ToCData<Address>(info->getter()) == 0) break; |
+ if (!info->IsCompatibleReceiver(*receiver)) break; |
+ return isolate()->stub_cache()->ComputeLoadCallback( |
+ name, receiver, holder, info); |
+ } else if (callback->IsAccessorPair()) { |
+ Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter()); |
+ if (!getter->IsJSFunction()) break; |
+ if (holder->IsGlobalObject()) break; |
+ if (!holder->HasFastProperties()) break; |
+ return isolate()->stub_cache()->ComputeLoadViaGetter( |
+ name, receiver, holder, Handle<JSFunction>::cast(getter)); |
+ } |
+ ASSERT(callback->IsForeign()); |
+ // No IC support for old-style native accessors. |
+ break; |
+ } |
+ case INTERCEPTOR: |
+ ASSERT(HasInterceptorGetter(*holder)); |
+ return isolate()->stub_cache()->ComputeLoadInterceptor( |
+ name, receiver, holder); |
+ default: |
+ break; |
+ } |
+ return Handle<Code>::null(); |
+} |
+ |
+ |
static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
// This helper implements a few common fast cases for converting |
// non-smi keys of keyed loads/stores to a smi or a string. |
@@ -1262,87 +1269,43 @@ MaybeObject* KeyedLoadIC::Load(State state, |
} |
-void KeyedLoadIC::UpdateLoadCaches(LookupResult* lookup, |
- State state, |
- Handle<Object> object, |
- Handle<String> name) { |
+Handle<Code> KeyedLoadIC::ComputeLoadMonomorphic(LookupResult* lookup, |
+ Handle<JSObject> receiver, |
+ Handle<String> name) { |
// Bail out if we didn't find a result. |
- if (!lookup->IsProperty() || !lookup->IsCacheable()) return; |
- |
- if (!object->IsJSObject()) return; |
- Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
- |
- if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
+ if (!lookup->IsProperty()) return Handle<Code>::null(); |
- // Compute the code stub for this load. |
- 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 { |
- // Compute a monomorphic stub. |
- Handle<JSObject> holder(lookup->holder()); |
- switch (lookup->type()) { |
- case FIELD: |
- code = isolate()->stub_cache()->ComputeKeyedLoadField( |
- name, receiver, holder, lookup->GetFieldIndex()); |
- break; |
- case CONSTANT_FUNCTION: { |
- Handle<JSFunction> constant(lookup->GetConstantFunction()); |
- code = isolate()->stub_cache()->ComputeKeyedLoadConstant( |
- name, receiver, holder, constant); |
- break; |
- } |
- case CALLBACKS: { |
- Handle<Object> callback_object(lookup->GetCallbackObject()); |
- if (!callback_object->IsAccessorInfo()) return; |
- Handle<AccessorInfo> callback = |
- Handle<AccessorInfo>::cast(callback_object); |
- if (v8::ToCData<Address>(callback->getter()) == 0) return; |
- if (!callback->IsCompatibleReceiver(*receiver)) return; |
- code = isolate()->stub_cache()->ComputeKeyedLoadCallback( |
- name, receiver, holder, callback); |
- break; |
- } |
- case INTERCEPTOR: |
- ASSERT(HasInterceptorGetter(lookup->holder())); |
- code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor( |
- name, receiver, holder); |
- break; |
- default: |
- // Always rewrite to the generic case so that we do not |
- // repeatedly try to rewrite. |
- code = generic_stub(); |
- break; |
+ // Compute a monomorphic stub. |
+ Handle<JSObject> holder(lookup->holder()); |
+ switch (lookup->type()) { |
+ case FIELD: |
+ return isolate()->stub_cache()->ComputeKeyedLoadField( |
+ name, receiver, holder, lookup->GetFieldIndex()); |
+ case CONSTANT_FUNCTION: { |
+ Handle<JSFunction> constant(lookup->GetConstantFunction()); |
+ return isolate()->stub_cache()->ComputeKeyedLoadConstant( |
+ name, receiver, holder, constant); |
} |
+ case CALLBACKS: { |
+ Handle<Object> callback_object(lookup->GetCallbackObject()); |
+ if (!callback_object->IsAccessorInfo()) break; |
+ Handle<AccessorInfo> callback = |
+ Handle<AccessorInfo>::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); |
+ } |
+ 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(); |
} |
- |
- // 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(*megamorphic_stub()); |
- } |
- break; |
- case MEGAMORPHIC: |
- case GENERIC: |
- case DEBUG_STUB: |
- break; |
- case MONOMORPHIC_PROTOTYPE_FAILURE: |
- UNREACHABLE(); |
- break; |
- } |
- |
- TRACE_IC("KeyedLoadIC", name, state, target()); |
+ return Handle<Code>::null(); |
} |