Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 43f84b41c71b468de183b34bebc46c953933a6d8..b77d4f3edb9f5dab53c3319b82b4d06d47a31025 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -4171,6 +4171,23 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) { |
} |
+MaybeObject* TransitionElements(Handle<Object> object, |
+ ElementsKind to_kind, |
+ Isolate* isolate) { |
+ HandleScope scope(isolate); |
+ if (!object->IsJSObject()) return isolate->ThrowIllegalOperation(); |
+ ElementsKind from_kind = |
+ Handle<JSObject>::cast(object)->map()->elements_kind(); |
+ if (Map::IsValidElementsTransition(from_kind, to_kind)) { |
+ Handle<Object> result = |
+ TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); |
+ if (result.is_null()) return isolate->ThrowIllegalOperation(); |
+ return *result; |
+ } |
+ return isolate->ThrowIllegalOperation(); |
+} |
+ |
+ |
// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric. |
RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { |
NoHandleAllocation ha; |
@@ -4187,40 +4204,63 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { |
// |
// Additionally, we need to make sure that we do not cache results |
// for objects that require access checks. |
- if (args[0]->IsJSObject() && |
- !args[0]->IsJSGlobalProxy() && |
- !args[0]->IsAccessCheckNeeded() && |
- args[1]->IsString()) { |
- JSObject* receiver = JSObject::cast(args[0]); |
- String* key = String::cast(args[1]); |
- if (receiver->HasFastProperties()) { |
- // Attempt to use lookup cache. |
- Map* receiver_map = receiver->map(); |
- KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache(); |
- int offset = keyed_lookup_cache->Lookup(receiver_map, key); |
- if (offset != -1) { |
- Object* value = receiver->FastPropertyAt(offset); |
- return value->IsTheHole() ? isolate->heap()->undefined_value() : value; |
- } |
- // Lookup cache miss. Perform lookup and update the cache if appropriate. |
- LookupResult result(isolate); |
- receiver->LocalLookup(key, &result); |
- if (result.IsProperty() && result.type() == FIELD) { |
- int offset = result.GetFieldIndex(); |
- keyed_lookup_cache->Update(receiver_map, key, offset); |
- return receiver->FastPropertyAt(offset); |
+ if (args[0]->IsJSObject()) { |
+ if (!args[0]->IsJSGlobalProxy() && |
+ !args[0]->IsAccessCheckNeeded() && |
+ args[1]->IsString()) { |
+ JSObject* receiver = JSObject::cast(args[0]); |
+ String* key = String::cast(args[1]); |
+ if (receiver->HasFastProperties()) { |
+ // Attempt to use lookup cache. |
+ Map* receiver_map = receiver->map(); |
+ KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache(); |
+ int offset = keyed_lookup_cache->Lookup(receiver_map, key); |
+ if (offset != -1) { |
+ Object* value = receiver->FastPropertyAt(offset); |
+ return value->IsTheHole() |
+ ? isolate->heap()->undefined_value() |
+ : value; |
+ } |
+ // Lookup cache miss. Perform lookup and update the cache if |
+ // appropriate. |
+ LookupResult result(isolate); |
+ receiver->LocalLookup(key, &result); |
+ if (result.IsProperty() && result.type() == FIELD) { |
+ int offset = result.GetFieldIndex(); |
+ keyed_lookup_cache->Update(receiver_map, key, offset); |
+ return receiver->FastPropertyAt(offset); |
+ } |
+ } else { |
+ // Attempt dictionary lookup. |
+ StringDictionary* dictionary = receiver->property_dictionary(); |
+ int entry = dictionary->FindEntry(key); |
+ if ((entry != StringDictionary::kNotFound) && |
+ (dictionary->DetailsAt(entry).type() == NORMAL)) { |
+ Object* value = dictionary->ValueAt(entry); |
+ if (!receiver->IsGlobalObject()) return value; |
+ value = JSGlobalPropertyCell::cast(value)->value(); |
+ if (!value->IsTheHole()) return value; |
+ // If value is the hole do the general lookup. |
+ } |
} |
- } else { |
- // Attempt dictionary lookup. |
- StringDictionary* dictionary = receiver->property_dictionary(); |
- int entry = dictionary->FindEntry(key); |
- if ((entry != StringDictionary::kNotFound) && |
- (dictionary->DetailsAt(entry).type() == NORMAL)) { |
- Object* value = dictionary->ValueAt(entry); |
- if (!receiver->IsGlobalObject()) return value; |
- value = JSGlobalPropertyCell::cast(value)->value(); |
- if (!value->IsTheHole()) return value; |
- // If value is the hole do the general lookup. |
+ } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) { |
+ // JSObject without a string key. If the key is a Smi, check for a |
+ // definite out-of-bounds access to elements, which is a strong indicator |
+ // that subsequent accesses will also call the runtime. Proactively |
+ // transition elements to FAST_ELEMENTS to avoid excessive boxing of |
+ // doubles for those future calls in the case that the elements would |
+ // become FAST_DOUBLE_ELEMENTS. |
+ Handle<JSObject> js_object(args.at<JSObject>(0)); |
+ ElementsKind elements_kind = js_object->GetElementsKind(); |
+ if (elements_kind == FAST_SMI_ONLY_ELEMENTS || |
+ elements_kind == FAST_DOUBLE_ELEMENTS) { |
+ FixedArrayBase* elements = js_object->elements(); |
+ if (args.at<Smi>(1)->value() >= elements->length()) { |
+ MaybeObject* maybe_object = TransitionElements(js_object, |
+ FAST_ELEMENTS, |
+ isolate); |
+ if (maybe_object->IsFailure()) return maybe_object; |
+ } |
} |
} |
} else if (args[0]->IsString() && args[1]->IsSmi()) { |
@@ -4609,23 +4649,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) { |
} |
-MaybeObject* TransitionElements(Handle<Object> object, |
- ElementsKind to_kind, |
- Isolate* isolate) { |
- HandleScope scope(isolate); |
- if (!object->IsJSObject()) return isolate->ThrowIllegalOperation(); |
- ElementsKind from_kind = |
- Handle<JSObject>::cast(object)->map()->elements_kind(); |
- if (Map::IsValidElementsTransition(from_kind, to_kind)) { |
- Handle<Object> result = |
- TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); |
- if (result.is_null()) return isolate->ThrowIllegalOperation(); |
- return *result; |
- } |
- return isolate->ThrowIllegalOperation(); |
-} |
- |
- |
RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) { |
NoHandleAllocation ha; |
RUNTIME_ASSERT(args.length() == 1); |