Commit 2d566c71 authored by verwaest@chromium.org's avatar verwaest@chromium.org

Merge UpdateStoreCaches into a single function dispatching on...

Merge UpdateStoreCaches into a single function dispatching on ComputeStoreMonorphic and UpdateMegamorphicCache.

Review URL: https://chromiumcodereview.appspot.com/12057003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13503 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a7e88a34
......@@ -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,7 +1447,7 @@ MaybeObject* StoreIC::Store(State state,
}
void StoreIC::UpdateStoreCaches(LookupResult* lookup,
void StoreIC::UpdateCaches(LookupResult* lookup,
State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
......@@ -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;
}
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,
Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
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<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();
}
......
......@@ -165,6 +165,21 @@ class IC {
static inline void SetTargetAtAddress(Address address, Code* target);
static void PostPatching(Address address, Code* target, Code* old_target);
void PatchCache(State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
Handle<String> name,
Handle<Code> code);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code);
virtual Handle<Code> megamorphic_stub() {
UNREACHABLE();
return Handle<Code>::null();
}
virtual Handle<Code> megamorphic_stub_strict() {
UNREACHABLE();
return Handle<Code>::null();
}
private:
// Frame pointer for the frame that uses (calls) the IC.
Address fp_;
......@@ -361,7 +376,6 @@ class LoadIC: public IC {
virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<String> name);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code);
private:
// Stub accessors.
......@@ -502,12 +516,19 @@ class StoreIC: public IC {
// Update the inline cache and the global stub cache based on the
// lookup result.
virtual void UpdateStoreCaches(LookupResult* lookup,
void UpdateCaches(LookupResult* lookup,
State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
Handle<String> name,
Handle<Object> value);
// 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.
virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
Handle<String> name);
private:
void set_target(Code* code) {
......@@ -607,13 +628,11 @@ class KeyedStoreIC: public StoreIC {
protected:
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
// Update the inline cache.
virtual void UpdateStoreCaches(LookupResult* lookup,
State state,
virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
Handle<String> name,
Handle<Object> value);
Handle<String> name);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code) { }
virtual Handle<Code> megamorphic_stub() {
return isolate()->builtins()->KeyedStoreIC_Generic();
......
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