Replace miss_mode flag with explicit Load/Store Force Generic methods.
R=ishell@chromium.org Review URL: https://chromiumcodereview.appspot.com/70233009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17774 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
14a25f1ede
commit
c3270daae6
118
src/ic.cc
118
src/ic.cc
@ -1346,9 +1346,14 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* KeyedLoadIC::Load(Handle<Object> object,
|
||||
Handle<Object> key,
|
||||
ICMissMode miss_mode) {
|
||||
MaybeObject* KeyedLoadIC::LoadForceGeneric(Handle<Object> object,
|
||||
Handle<Object> key) {
|
||||
set_target(*generic_stub());
|
||||
return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* KeyedLoadIC::Load(Handle<Object> object, Handle<Object> key) {
|
||||
if (MigrateDeprecated(object)) {
|
||||
return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
|
||||
}
|
||||
@ -1365,20 +1370,18 @@ MaybeObject* KeyedLoadIC::Load(Handle<Object> object,
|
||||
if (maybe_object->IsFailure()) return maybe_object;
|
||||
} else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
|
||||
ASSERT(!object->IsJSGlobalProxy());
|
||||
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 (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1928,10 +1931,23 @@ KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* KeyedStoreIC::StoreForceGeneric(Handle<Object> object,
|
||||
Handle<Object> key,
|
||||
Handle<Object> value) {
|
||||
set_target(*generic_stub());
|
||||
Handle<Object> result = Runtime::SetObjectProperty(isolate(), object,
|
||||
key,
|
||||
value,
|
||||
NONE,
|
||||
strict_mode());
|
||||
RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
|
||||
Handle<Object> key,
|
||||
Handle<Object> value,
|
||||
ICMissMode miss_mode) {
|
||||
Handle<Object> value) {
|
||||
if (MigrateDeprecated(object)) {
|
||||
Handle<Object> result = Runtime::SetObjectProperty(isolate(), object,
|
||||
key,
|
||||
@ -1970,24 +1986,22 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
|
||||
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()))) {
|
||||
// We should go generic if receiver isn't a dictionary, but our
|
||||
// prototype chain does have dictionary elements. This ensures that
|
||||
// other non-dictionary receivers in the polymorphic case benefit
|
||||
// from fast path keyed stores.
|
||||
if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) {
|
||||
KeyedAccessStoreMode store_mode =
|
||||
GetStoreMode(receiver, key, value);
|
||||
stub = StoreElementStub(receiver, store_mode);
|
||||
}
|
||||
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()))) {
|
||||
// We should go generic if receiver isn't a dictionary, but our
|
||||
// prototype chain does have dictionary elements. This ensures that
|
||||
// other non-dictionary receivers in the polymorphic case benefit
|
||||
// from fast path keyed stores.
|
||||
if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) {
|
||||
KeyedAccessStoreMode store_mode =
|
||||
GetStoreMode(receiver, key, value);
|
||||
stub = StoreElementStub(receiver, store_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2086,7 +2100,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
|
||||
Handle<Object> receiver = args.at<Object>(0);
|
||||
Handle<Object> key = args.at<Object>(1);
|
||||
ic.UpdateState(receiver, key);
|
||||
return ic.Load(receiver, key, MISS);
|
||||
return ic.Load(receiver, key);
|
||||
}
|
||||
|
||||
|
||||
@ -2097,7 +2111,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) {
|
||||
Handle<Object> receiver = args.at<Object>(0);
|
||||
Handle<Object> key = args.at<Object>(1);
|
||||
ic.UpdateState(receiver, key);
|
||||
return ic.Load(receiver, key, MISS);
|
||||
return ic.Load(receiver, key);
|
||||
}
|
||||
|
||||
|
||||
@ -2108,7 +2122,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
|
||||
Handle<Object> receiver = args.at<Object>(0);
|
||||
Handle<Object> key = args.at<Object>(1);
|
||||
ic.UpdateState(receiver, key);
|
||||
return ic.Load(receiver, key, MISS_FORCE_GENERIC);
|
||||
return ic.LoadForceGeneric(receiver, key);
|
||||
}
|
||||
|
||||
|
||||
@ -2217,7 +2231,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
|
||||
Handle<Object> receiver = args.at<Object>(0);
|
||||
Handle<Object> key = args.at<Object>(1);
|
||||
ic.UpdateState(receiver, key);
|
||||
return ic.Store(receiver, key, args.at<Object>(2), MISS);
|
||||
return ic.Store(receiver, key, args.at<Object>(2));
|
||||
}
|
||||
|
||||
|
||||
@ -2228,7 +2242,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) {
|
||||
Handle<Object> receiver = args.at<Object>(0);
|
||||
Handle<Object> key = args.at<Object>(1);
|
||||
ic.UpdateState(receiver, key);
|
||||
return ic.Store(receiver, key, args.at<Object>(2), MISS);
|
||||
return ic.Store(receiver, key, args.at<Object>(2));
|
||||
}
|
||||
|
||||
|
||||
@ -2273,7 +2287,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
|
||||
Handle<Object> receiver = args.at<Object>(0);
|
||||
Handle<Object> key = args.at<Object>(1);
|
||||
ic.UpdateState(receiver, key);
|
||||
return ic.Store(receiver, key, args.at<Object>(2), MISS_FORCE_GENERIC);
|
||||
return ic.StoreForceGeneric(receiver, key, args.at<Object>(2));
|
||||
}
|
||||
|
||||
|
||||
@ -2560,7 +2574,7 @@ CompareIC::State CompareIC::TargetState(State old_state,
|
||||
}
|
||||
|
||||
|
||||
void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
|
||||
Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
|
||||
HandleScope scope(isolate());
|
||||
State previous_left, previous_right, previous_state;
|
||||
ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left,
|
||||
@ -2574,7 +2588,8 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
|
||||
stub.set_known_map(
|
||||
Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
|
||||
}
|
||||
set_target(*stub.GetCode(isolate()));
|
||||
Handle<Code> new_target = stub.GetCode(isolate());
|
||||
set_target(*new_target);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (FLAG_trace_ic) {
|
||||
@ -2596,6 +2611,8 @@ void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
|
||||
if (previous_state == UNINITIALIZED) {
|
||||
PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
|
||||
}
|
||||
|
||||
return *new_target;
|
||||
}
|
||||
|
||||
|
||||
@ -2604,8 +2621,7 @@ RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 3);
|
||||
CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
|
||||
ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
|
||||
return ic.raw_target();
|
||||
return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
|
||||
}
|
||||
|
||||
|
||||
@ -2716,9 +2732,8 @@ Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object,
|
||||
Code::ExtraICState extra_ic_state) {
|
||||
ToBooleanStub stub(extra_ic_state);
|
||||
MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object) {
|
||||
ToBooleanStub stub(target()->extended_extra_ic_state());
|
||||
bool to_boolean_value = stub.UpdateStatus(object);
|
||||
Handle<Code> code = stub.GetCode(isolate());
|
||||
set_target(*code);
|
||||
@ -2731,8 +2746,7 @@ RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<Object> object = args.at<Object>(0);
|
||||
ToBooleanIC ic(isolate);
|
||||
Code::ExtraICState extra_ic_state = ic.target()->extended_extra_ic_state();
|
||||
return ic.ToBoolean(object, extra_ic_state);
|
||||
return ic.ToBoolean(object);
|
||||
}
|
||||
|
||||
|
||||
|
43
src/ic.h
43
src/ic.h
@ -94,10 +94,6 @@ class IC {
|
||||
IC(FrameDepth depth, Isolate* isolate);
|
||||
virtual ~IC() {}
|
||||
|
||||
// Get the call-site target; used for determining the state.
|
||||
Handle<Code> target() const { return target_; }
|
||||
Code* raw_target() const { return GetTargetAtAddress(address()); }
|
||||
|
||||
State state() const { return state_; }
|
||||
inline Address address() const;
|
||||
|
||||
@ -130,6 +126,20 @@ class IC {
|
||||
return ComputeMode() == RelocInfo::CODE_TARGET_CONTEXT;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsLoadStub() {
|
||||
return target()->is_load_stub() || target()->is_keyed_load_stub();
|
||||
}
|
||||
|
||||
bool IsStoreStub() {
|
||||
return target()->is_store_stub() || target()->is_keyed_store_stub();
|
||||
}
|
||||
|
||||
bool IsCallStub() {
|
||||
return target()->is_call_stub() || target()->is_keyed_call_stub();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Determines which map must be used for keeping the code stub.
|
||||
// These methods should not be called with undefined or null.
|
||||
static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object);
|
||||
@ -146,6 +156,9 @@ class IC {
|
||||
}
|
||||
|
||||
protected:
|
||||
// Get the call-site target; used for determining the state.
|
||||
Handle<Code> target() const { return target_; }
|
||||
|
||||
Address fp() const { return fp_; }
|
||||
Address pc() const { return *pc_address_; }
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
@ -229,6 +242,8 @@ class IC {
|
||||
void TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name);
|
||||
|
||||
private:
|
||||
Code* raw_target() const { return GetTargetAtAddress(address()); }
|
||||
|
||||
// Frame pointer for the frame that uses (calls) the IC.
|
||||
Address fp_;
|
||||
|
||||
@ -391,7 +406,7 @@ class KeyedCallIC: public CallICBase {
|
||||
class LoadIC: public IC {
|
||||
public:
|
||||
explicit LoadIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) {
|
||||
ASSERT(target()->is_load_stub() || target()->is_keyed_load_stub());
|
||||
ASSERT(IsLoadStub());
|
||||
}
|
||||
|
||||
// Code generator routines.
|
||||
@ -468,9 +483,11 @@ class KeyedLoadIC: public LoadIC {
|
||||
ASSERT(target()->is_keyed_load_stub());
|
||||
}
|
||||
|
||||
MUST_USE_RESULT MaybeObject* LoadForceGeneric(Handle<Object> object,
|
||||
Handle<Object> key);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* Load(Handle<Object> object,
|
||||
Handle<Object> key,
|
||||
ICMissMode force_generic);
|
||||
Handle<Object> key);
|
||||
|
||||
// Code generator routines.
|
||||
static void GenerateMiss(MacroAssembler* masm, ICMissMode force_generic);
|
||||
@ -542,7 +559,7 @@ class StoreIC: public IC {
|
||||
StoreIC(FrameDepth depth, Isolate* isolate)
|
||||
: IC(depth, isolate),
|
||||
strict_mode_(Code::GetStrictMode(target()->extra_ic_state())) {
|
||||
ASSERT(target()->is_store_stub() || target()->is_keyed_store_stub());
|
||||
ASSERT(IsStoreStub());
|
||||
}
|
||||
|
||||
virtual StrictModeFlag strict_mode() const { return strict_mode_; }
|
||||
@ -670,10 +687,12 @@ class KeyedStoreIC: public StoreIC {
|
||||
ASSERT(target()->is_keyed_store_stub());
|
||||
}
|
||||
|
||||
MUST_USE_RESULT MaybeObject* StoreForceGeneric(Handle<Object> object,
|
||||
Handle<Object> name,
|
||||
Handle<Object> value);
|
||||
MUST_USE_RESULT MaybeObject* Store(Handle<Object> object,
|
||||
Handle<Object> name,
|
||||
Handle<Object> value,
|
||||
ICMissMode force_generic);
|
||||
Handle<Object> value);
|
||||
|
||||
// Code generators for stub routines. Only called once at startup.
|
||||
static void GenerateInitialize(MacroAssembler* masm) {
|
||||
@ -826,7 +845,7 @@ class CompareIC: public IC {
|
||||
: IC(EXTRA_CALL_FRAME, isolate), op_(op) { }
|
||||
|
||||
// Update the inline cache for the given operands.
|
||||
void UpdateCaches(Handle<Object> x, Handle<Object> y);
|
||||
Code* UpdateCaches(Handle<Object> x, Handle<Object> y);
|
||||
|
||||
|
||||
// Factory method for getting an uninitialized compare stub.
|
||||
@ -879,7 +898,7 @@ class ToBooleanIC: public IC {
|
||||
public:
|
||||
explicit ToBooleanIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
|
||||
|
||||
MaybeObject* ToBoolean(Handle<Object> object, Code::ExtraICState state);
|
||||
MaybeObject* ToBoolean(Handle<Object> object);
|
||||
};
|
||||
|
||||
|
||||
|
@ -830,7 +830,7 @@ static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) {
|
||||
// can't use either LoadIC or KeyedLoadIC constructors.
|
||||
HandleScope scope(isolate);
|
||||
IC ic(IC::NO_EXTRA_FRAME, isolate);
|
||||
ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
|
||||
ASSERT(ic.IsLoadStub());
|
||||
if (!ic.SlowIsUndeclaredGlobal()) return isolate->heap()->undefined_value();
|
||||
|
||||
// Throw a reference error.
|
||||
|
Loading…
Reference in New Issue
Block a user