Merge Store from Keyed and Named store.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13461 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2013-01-22 09:48:59 +00:00
parent 3ffcbe3319
commit 2c070e2300
2 changed files with 158 additions and 185 deletions

213
src/ic.cc
View File

@ -351,11 +351,9 @@ void IC::Clear(Address address) {
switch (target->kind()) { switch (target->kind()) {
case Code::LOAD_IC: return LoadIC::Clear(address, target); case Code::LOAD_IC: return LoadIC::Clear(address, target);
case Code::KEYED_LOAD_IC: case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target);
return KeyedLoadIC::Clear(address, target);
case Code::STORE_IC: return StoreIC::Clear(address, target); case Code::STORE_IC: return StoreIC::Clear(address, target);
case Code::KEYED_STORE_IC: case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
return KeyedStoreIC::Clear(address, target);
case Code::CALL_IC: return CallIC::Clear(address, target); case Code::CALL_IC: return CallIC::Clear(address, target);
case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
case Code::COMPARE_IC: return CompareIC::Clear(address, target); case Code::COMPARE_IC: return CompareIC::Clear(address, target);
@ -387,13 +385,13 @@ void KeyedLoadIC::Clear(Address address, Code* target) {
// Make sure to also clear the map used in inline fast cases. If we // Make sure to also clear the map used in inline fast cases. If we
// do not clear these maps, cached code can keep objects alive // do not clear these maps, cached code can keep objects alive
// through the embedded maps. // through the embedded maps.
SetTargetAtAddress(address, initialize_stub()); SetTargetAtAddress(address, *initialize_stub());
} }
void LoadIC::Clear(Address address, Code* target) { void LoadIC::Clear(Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return; if (target->ic_state() == UNINITIALIZED) return;
SetTargetAtAddress(address, initialize_stub()); SetTargetAtAddress(address, *initialize_stub());
} }
@ -401,8 +399,8 @@ void StoreIC::Clear(Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return; if (target->ic_state() == UNINITIALIZED) return;
SetTargetAtAddress(address, SetTargetAtAddress(address,
(Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode)
? initialize_stub_strict() ? *initialize_stub_strict()
: initialize_stub()); : *initialize_stub());
} }
@ -410,8 +408,8 @@ void KeyedStoreIC::Clear(Address address, Code* target) {
if (target->ic_state() == UNINITIALIZED) return; if (target->ic_state() == UNINITIALIZED) return;
SetTargetAtAddress(address, SetTargetAtAddress(address,
(Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode)
? initialize_stub_strict() ? *initialize_stub_strict()
: initialize_stub()); : *initialize_stub());
} }
@ -1313,34 +1311,34 @@ static bool LookupForWrite(Handle<JSObject> receiver,
} }
MaybeObject* StoreIC::Store(State state, MaybeObject* IC::Store(State state,
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
Handle<Object> object, Handle<Object> object,
Handle<String> name, Handle<String> name,
Handle<Object> value) { Handle<Object> value,
if (!object->IsJSObject()) { JSReceiver::StoreFromKeyed store_mode) {
// Handle proxies. // Handle proxies.
if (object->IsJSProxy()) { if (object->IsJSProxy()) {
return JSProxy::cast(*object)-> return JSProxy::cast(*object)->
SetProperty(*name, *value, NONE, strict_mode); SetProperty(*name, *value, NONE, strict_mode);
}
// If the object is undefined or null it's illegal to try to set any
// properties on it; throw a TypeError in that case.
if (object->IsUndefined() || object->IsNull()) {
return TypeError("non_object_property_store", object, name);
}
// The length property of string values is read-only. Throw in strict mode.
if (strict_mode == kStrictMode && object->IsString() &&
name->Equals(isolate()->heap()->length_symbol())) {
return TypeError("strict_read_only_property", object, name);
}
// Ignore other stores where the receiver is not a JSObject.
// TODO(1475): Must check prototype chains of object wrappers.
return *value;
} }
// If the object is undefined or null it's illegal to try to set any
// properties on it; throw a TypeError in that case.
if (object->IsUndefined() || object->IsNull()) {
return TypeError("non_object_property_store", object, name);
}
// The length property of string values is read-only. Throw in strict mode.
if (strict_mode == kStrictMode && object->IsString() &&
name->Equals(isolate()->heap()->length_symbol())) {
return TypeError("strict_read_only_property", object, name);
}
// Ignore other stores where the receiver is not a JSObject.
// TODO(1475): Must check prototype chains of object wrappers.
if (!object->IsJSObject()) return *value;
Handle<JSObject> receiver = Handle<JSObject>::cast(object); Handle<JSObject> receiver = Handle<JSObject>::cast(object);
// Check if the given name is an array index. // Check if the given name is an array index.
@ -1354,75 +1352,63 @@ MaybeObject* StoreIC::Store(State state,
// Observed objects are always modified through the runtime. // Observed objects are always modified through the runtime.
if (FLAG_harmony_observation && receiver->map()->is_observed()) { if (FLAG_harmony_observation && receiver->map()->is_observed()) {
return receiver->SetProperty(*name, *value, NONE, strict_mode); return receiver->SetProperty(*name, *value, NONE, strict_mode, store_mode);
} }
// Use specialized code for setting the length of arrays with fast // Use specialized code for setting the length of arrays with fast
// properties. Slow properties might indicate redefinition of the // properties. Slow properties might indicate redefinition of the length
// length property. // property.
if (receiver->IsJSArray() && if (FLAG_use_ic &&
receiver->IsJSArray() &&
name->Equals(isolate()->heap()->length_symbol()) && name->Equals(isolate()->heap()->length_symbol()) &&
Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
receiver->HasFastProperties()) { receiver->HasFastProperties() &&
#ifdef DEBUG kind() != Code::KEYED_STORE_IC) {
if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
#endif
Handle<Code> stub = (strict_mode == kStrictMode) Handle<Code> stub = (strict_mode == kStrictMode)
? isolate()->builtins()->StoreIC_ArrayLength_Strict() ? isolate()->builtins()->StoreIC_ArrayLength_Strict()
: isolate()->builtins()->StoreIC_ArrayLength(); : isolate()->builtins()->StoreIC_ArrayLength();
set_target(*stub); set_target(*stub);
return receiver->SetProperty(*name, *value, NONE, strict_mode); TRACE_IC("StoreIC", name, state, *stub);
} return receiver->SetProperty(*name, *value, NONE, strict_mode, store_mode);
// Lookup the property locally in the receiver.
if (!receiver->IsJSGlobalProxy()) {
LookupResult lookup(isolate());
if (LookupForWrite(receiver, name, &lookup)) {
if (FLAG_use_ic) { // Generate a stub for this store.
UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
}
} else {
// Strict mode doesn't allow setting non-existent global property
// or an assignment to a read only property.
if (strict_mode == kStrictMode) {
if (lookup.IsProperty() && lookup.IsReadOnly()) {
return TypeError("strict_read_only_property", object, name);
} else if (IsContextual(object)) {
return ReferenceError("not_defined", name);
}
}
}
} }
if (receiver->IsJSGlobalProxy()) { if (receiver->IsJSGlobalProxy()) {
// TODO(ulan): find out why we patch this site even with --no-use-ic if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) {
// Generate a generic stub that goes to the runtime when we see a global // Generate a generic stub that goes to the runtime when we see a global
// proxy as receiver. // proxy as receiver.
Handle<Code> stub = (strict_mode == kStrictMode) Handle<Code> stub = (strict_mode == kStrictMode)
? global_proxy_stub_strict() ? global_proxy_stub_strict()
: global_proxy_stub(); : global_proxy_stub();
if (target() != *stub) {
set_target(*stub); set_target(*stub);
TRACE_IC("StoreIC", name, state, target()); TRACE_IC("StoreIC", name, state, *stub);
} }
return receiver->SetProperty(*name, *value, NONE, strict_mode, store_mode);
}
LookupResult lookup(isolate());
if (LookupForWrite(receiver, name, &lookup)) {
if (FLAG_use_ic) {
UpdateStoreCaches(&lookup, state, strict_mode, receiver, name, value);
}
} else if (strict_mode == kStrictMode &&
!lookup.IsFound() &&
IsContextual(object)) {
// Strict mode doesn't allow setting non-existent global property
// or an assignment to a read only property.
return ReferenceError("not_defined", name);
} }
// Set the property. // Set the property.
return receiver->SetProperty(*name, return receiver->SetProperty(*name, *value, NONE, strict_mode, store_mode);
*value,
NONE,
strict_mode,
JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
} }
void StoreIC::UpdateCaches(LookupResult* lookup, void StoreIC::UpdateStoreCaches(LookupResult* lookup,
State state, State state,
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
Handle<JSObject> receiver, Handle<JSObject> receiver,
Handle<String> name, Handle<String> name,
Handle<Object> value) { Handle<Object> value) {
ASSERT(!receiver->IsJSGlobalProxy()); ASSERT(!receiver->IsJSGlobalProxy());
ASSERT(StoreICableLookup(lookup)); ASSERT(StoreICableLookup(lookup));
ASSERT(lookup->IsFound()); ASSERT(lookup->IsFound());
@ -1531,7 +1517,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
} }
isolate()->stub_cache()->Set(*name, receiver->map(), *code); isolate()->stub_cache()->Set(*name, receiver->map(), *code);
set_target((strict_mode == kStrictMode) set_target((strict_mode == kStrictMode)
? megamorphic_stub_strict() ? *megamorphic_stub_strict()
: *megamorphic_stub()); : *megamorphic_stub());
} }
break; break;
@ -1891,43 +1877,12 @@ MaybeObject* KeyedStoreIC::Store(State state,
if (key->IsSymbol()) { if (key->IsSymbol()) {
Handle<String> name = Handle<String>::cast(key); Handle<String> name = Handle<String>::cast(key);
return IC::Store(state,
// Handle proxies. strict_mode,
if (object->IsJSProxy()) { object,
return JSProxy::cast(*object)->SetProperty( name,
*name, *value, NONE, strict_mode); value,
} JSReceiver::MAY_BE_STORE_FROM_KEYED);
// If the object is undefined or null it's illegal to try to set any
// properties on it; throw a TypeError in that case.
if (object->IsUndefined() || object->IsNull()) {
return TypeError("non_object_property_store", object, name);
}
// Ignore stores where the receiver is not a JSObject.
if (!object->IsJSObject()) return *value;
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
// Check if the given name is an array index.
uint32_t index;
if (name->AsArrayIndex(&index)) {
Handle<Object> result =
JSObject::SetElement(receiver, index, value, NONE, strict_mode);
RETURN_IF_EMPTY_HANDLE(isolate(), result);
return *value;
}
// Update inline cache and stub cache.
if (FLAG_use_ic && !receiver->IsJSGlobalProxy() &&
!(FLAG_harmony_observation && receiver->map()->is_observed())) {
LookupResult lookup(isolate());
if (LookupForWrite(receiver, name, &lookup)) {
UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
}
}
// Set the property.
return receiver->SetProperty(*name, *value, NONE, strict_mode);
} }
// Do not use ICs for objects that require access checks (including // Do not use ICs for objects that require access checks (including
@ -1966,12 +1921,12 @@ MaybeObject* KeyedStoreIC::Store(State state,
} }
void KeyedStoreIC::UpdateCaches(LookupResult* lookup, void KeyedStoreIC::UpdateStoreCaches(LookupResult* lookup,
State state, State state,
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
Handle<JSObject> receiver, Handle<JSObject> receiver,
Handle<String> name, Handle<String> name,
Handle<Object> value) { Handle<Object> value) {
ASSERT(!receiver->IsJSGlobalProxy()); ASSERT(!receiver->IsJSGlobalProxy());
ASSERT(StoreICableLookup(lookup)); ASSERT(StoreICableLookup(lookup));
ASSERT(lookup->IsFound()); ASSERT(lookup->IsFound());

130
src/ic.h
View File

@ -136,6 +136,15 @@ class IC {
Handle<Object> object, Handle<Object> object,
Handle<String> name); Handle<String> name);
MUST_USE_RESULT MaybeObject* Store(
State state,
StrictModeFlag strict_mode,
Handle<Object> object,
Handle<String> name,
Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode =
JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
protected: protected:
virtual Handle<Code> pre_monomorphic_stub() { virtual Handle<Code> pre_monomorphic_stub() {
UNREACHABLE(); UNREACHABLE();
@ -145,6 +154,10 @@ class IC {
UNREACHABLE(); UNREACHABLE();
return Handle<Code>::null(); return Handle<Code>::null();
} }
virtual Handle<Code> megamorphic_stub_strict() {
UNREACHABLE();
return Handle<Code>::null();
}
virtual Handle<Code> generic_stub() const { virtual Handle<Code> generic_stub() const {
UNREACHABLE(); UNREACHABLE();
return Handle<Code>::null(); return Handle<Code>::null();
@ -153,12 +166,29 @@ class IC {
UNREACHABLE(); UNREACHABLE();
return Code::STUB; return Code::STUB;
} }
virtual Handle<Code> global_proxy_stub() {
UNREACHABLE();
return Handle<Code>::null();
}
virtual Handle<Code> global_proxy_stub_strict() {
UNREACHABLE();
return Handle<Code>::null();
}
virtual void UpdateLoadCaches(LookupResult* lookup, virtual void UpdateLoadCaches(LookupResult* lookup,
State state, State state,
Handle<Object> object, Handle<Object> object,
Handle<String> name) { Handle<String> name) {
UNREACHABLE(); UNREACHABLE();
} }
virtual void UpdateStoreCaches(LookupResult* lookup,
State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
Handle<String> name,
Handle<Object> value) {
UNREACHABLE();
}
Address fp() const { return fp_; } Address fp() const { return fp_; }
Address pc() const { return *pc_address_; } Address pc() const { return *pc_address_; }
Isolate* isolate() const { return isolate_; } Isolate* isolate() const { return isolate_; }
@ -378,9 +408,8 @@ class LoadIC: public IC {
private: private:
// Stub accessors. // Stub accessors.
static Code* initialize_stub() { static Handle<Code> initialize_stub() {
return Isolate::Current()->builtins()->builtin( return Isolate::Current()->builtins()->LoadIC_Initialize();
Builtins::kLoadIC_Initialize);
} }
virtual Handle<Code> pre_monomorphic_stub() { virtual Handle<Code> pre_monomorphic_stub() {
return isolate()->builtins()->LoadIC_PreMonomorphic(); return isolate()->builtins()->LoadIC_PreMonomorphic();
@ -565,9 +594,8 @@ class KeyedLoadIC: public KeyedIC {
private: private:
// Stub accessors. // Stub accessors.
static Code* initialize_stub() { static Handle<Code> initialize_stub() {
return Isolate::Current()->builtins()->builtin( return Isolate::Current()->builtins()->KeyedLoadIC_Initialize();
Builtins::kKeyedLoadIC_Initialize);
} }
virtual Handle<Code> pre_monomorphic_stub() { virtual Handle<Code> pre_monomorphic_stub() {
return isolate()->builtins()->KeyedLoadIC_PreMonomorphic(); return isolate()->builtins()->KeyedLoadIC_PreMonomorphic();
@ -591,12 +619,6 @@ class StoreIC: public IC {
ASSERT(target()->is_store_stub()); ASSERT(target()->is_store_stub());
} }
MUST_USE_RESULT MaybeObject* Store(State state,
StrictModeFlag strict_mode,
Handle<Object> object,
Handle<String> name,
Handle<Object> value);
// Code generators for stub routines. Only called once at startup. // Code generators for stub routines. Only called once at startup.
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
static void GenerateMiss(MacroAssembler* masm); static void GenerateMiss(MacroAssembler* masm);
@ -612,17 +634,28 @@ class StoreIC: public IC {
virtual Handle<Code> megamorphic_stub() { virtual Handle<Code> megamorphic_stub() {
return isolate()->builtins()->StoreIC_Megamorphic(); return isolate()->builtins()->StoreIC_Megamorphic();
} }
// Stub accessors.
virtual Handle<Code> megamorphic_stub_strict() {
return isolate()->builtins()->StoreIC_Megamorphic_Strict();
}
virtual Handle<Code> global_proxy_stub() {
return isolate()->builtins()->StoreIC_GlobalProxy();
}
virtual Handle<Code> global_proxy_stub_strict() {
return isolate()->builtins()->StoreIC_GlobalProxy_Strict();
}
private:
// Update the inline cache and the global stub cache based on the // Update the inline cache and the global stub cache based on the
// lookup result. // lookup result.
void UpdateCaches(LookupResult* lookup, virtual void UpdateStoreCaches(LookupResult* lookup,
State state, State state,
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
Handle<JSObject> receiver, Handle<JSObject> receiver,
Handle<String> name, Handle<String> name,
Handle<Object> value); Handle<Object> value);
private:
void set_target(Code* code) { void set_target(Code* code) {
// Strict mode must be preserved across IC patching. // Strict mode must be preserved across IC patching.
ASSERT(Code::GetStrictMode(code->extra_ic_state()) == ASSERT(Code::GetStrictMode(code->extra_ic_state()) ==
@ -630,26 +663,12 @@ class StoreIC: public IC {
IC::set_target(code); IC::set_target(code);
} }
// Stub accessors. static Handle<Code> initialize_stub() {
Code* megamorphic_stub_strict() { return Isolate::Current()->builtins()->StoreIC_Initialize();
return isolate()->builtins()->builtin(
Builtins::kStoreIC_Megamorphic_Strict);
} }
static Code* initialize_stub() { static Handle<Code> initialize_stub_strict() {
return Isolate::Current()->builtins()->builtin( return Isolate::Current()->builtins()->StoreIC_Initialize_Strict();
Builtins::kStoreIC_Initialize);
} }
static Code* initialize_stub_strict() {
return Isolate::Current()->builtins()->builtin(
Builtins::kStoreIC_Initialize_Strict);
}
Handle<Code> global_proxy_stub() {
return isolate()->builtins()->StoreIC_GlobalProxy();
}
Handle<Code> global_proxy_stub_strict() {
return isolate()->builtins()->StoreIC_GlobalProxy_Strict();
}
static void Clear(Address address, Code* target); static void Clear(Address address, Code* target);
friend class IC; friend class IC;
@ -706,15 +725,22 @@ class KeyedStoreIC: public KeyedIC {
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
KeyedAccessGrowMode grow_mode); KeyedAccessGrowMode grow_mode);
private:
// Update the inline cache. // Update the inline cache.
void UpdateCaches(LookupResult* lookup, virtual void UpdateStoreCaches(LookupResult* lookup,
State state, State state,
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
Handle<JSObject> receiver, Handle<JSObject> receiver,
Handle<String> name, Handle<String> name,
Handle<Object> value); Handle<Object> value);
virtual Handle<Code> megamorphic_stub() {
return isolate()->builtins()->KeyedStoreIC_Generic();
}
virtual Handle<Code> megamorphic_stub_strict() {
return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
}
private:
void set_target(Code* code) { void set_target(Code* code) {
// Strict mode must be preserved across IC patching. // Strict mode must be preserved across IC patching.
ASSERT(Code::GetStrictMode(code->extra_ic_state()) == ASSERT(Code::GetStrictMode(code->extra_ic_state()) ==
@ -723,19 +749,11 @@ class KeyedStoreIC: public KeyedIC {
} }
// Stub accessors. // Stub accessors.
static Code* initialize_stub() { static Handle<Code> initialize_stub() {
return Isolate::Current()->builtins()->builtin( return Isolate::Current()->builtins()->KeyedStoreIC_Initialize();
Builtins::kKeyedStoreIC_Initialize);
} }
static Code* initialize_stub_strict() { static Handle<Code> initialize_stub_strict() {
return Isolate::Current()->builtins()->builtin( return Isolate::Current()->builtins()->KeyedStoreIC_Initialize_Strict();
Builtins::kKeyedStoreIC_Initialize_Strict);
}
Handle<Code> megamorphic_stub() {
return isolate()->builtins()->KeyedStoreIC_Generic();
}
Handle<Code> megamorphic_stub_strict() {
return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
} }
Handle<Code> generic_stub() const { Handle<Code> generic_stub() const {
return isolate()->builtins()->KeyedStoreIC_Generic(); return isolate()->builtins()->KeyedStoreIC_Generic();