Commit dd92c41a authored by verwaest@chromium.org's avatar verwaest@chromium.org

Merge UpdateLoadCaches into a single function dispatching on

ComputeLoadMonorphic and UpdateMegamorphicCache.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13492 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ef4d9d12
......@@ -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();
}
......
......@@ -354,10 +354,14 @@ class LoadIC: public IC {
// Update the inline cache and the global stub cache based on the
// lookup result.
virtual void UpdateLoadCaches(LookupResult* lookup,
State state,
Handle<Object> object,
Handle<String> name);
void UpdateCaches(LookupResult* lookup,
State state,
Handle<Object> object,
Handle<String> name);
virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<String> name);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code);
private:
// Stub accessors.
......@@ -425,10 +429,10 @@ class KeyedLoadIC: public LoadIC {
}
// Update the inline cache.
virtual void UpdateLoadCaches(LookupResult* lookup,
State state,
Handle<Object> object,
Handle<String> name);
virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<String> name);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code) { }
private:
// Stub accessors.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment