Chromium Code Reviews| Index: src/runtime/runtime-object.cc |
| diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc |
| index e0e3764837a4cfdfb1d84b49db528127604e5c19..dd35fb6e17a8a2d59598657da704a8ae38599d9a 100644 |
| --- a/src/runtime/runtime-object.cc |
| +++ b/src/runtime/runtime-object.cc |
| @@ -26,7 +26,8 @@ static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { |
| MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate, |
| Handle<Object> object, |
| - uint32_t index) { |
| + uint32_t index, |
| + Strength strength) { |
| // Handle [] indexing on Strings |
| if (object->IsString() && |
| index < static_cast<uint32_t>(String::cast(*object)->length())) { |
| @@ -34,7 +35,7 @@ MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate, |
| if (!result->IsUndefined()) return result; |
| } |
| - return Object::GetElement(isolate, object, index); |
| + return Object::GetElement(isolate, object, index, strength); |
| } |
| @@ -52,7 +53,8 @@ MaybeHandle<Name> Runtime::ToName(Isolate* isolate, Handle<Object> key) { |
| MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, |
| Handle<Object> object, |
| - Handle<Object> key) { |
| + Handle<Object> key, |
| + Strength strength) { |
| if (object->IsUndefined() || object->IsNull()) { |
| THROW_NEW_ERROR( |
| isolate, |
| @@ -63,7 +65,7 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, |
| // Check if the given key is an array index. |
| uint32_t index = 0; |
| if (key->ToArrayIndex(&index)) { |
| - return GetElementOrCharAt(isolate, object, index); |
| + return GetElementOrCharAt(isolate, object, index, strength); |
| } |
| // Convert the key to a name - possibly by calling back into JavaScript. |
| @@ -75,8 +77,115 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, |
| if (name->AsArrayIndex(&index)) { |
| return GetElementOrCharAt(isolate, object, index); |
| } else { |
| - return Object::GetProperty(object, name); |
| + return Object::GetProperty(object, name, strength); |
| + } |
| +} |
| + |
| + |
| +MUST_USE_RESULT static MaybeHandle<Object> TransitionElements( |
| + Handle<Object> object, ElementsKind to_kind, Isolate* isolate) { |
| + HandleScope scope(isolate); |
| + if (!object->IsJSObject()) { |
| + isolate->ThrowIllegalOperation(); |
| + return MaybeHandle<Object>(); |
| + } |
| + ElementsKind from_kind = |
| + Handle<JSObject>::cast(object)->map()->elements_kind(); |
| + if (Map::IsValidElementsTransition(from_kind, to_kind)) { |
| + JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); |
| + return object; |
| + } |
| + isolate->ThrowIllegalOperation(); |
| + return MaybeHandle<Object>(); |
| +} |
| + |
| + |
| +MaybeHandle<Object> Runtime::KeyedGetObjectProperty(Isolate* isolate, |
| + Handle<Object> receiver_obj, |
| + Handle<Object> key_obj, |
| + Strength strength) { |
| + // Fast cases for getting named properties of the receiver JSObject |
| + // itself. |
| + // |
| + // The global proxy objects has to be excluded since LookupOwn on |
| + // the global proxy object can return a valid result even though the |
| + // global proxy object never has properties. This is the case |
| + // because the global proxy object forwards everything to its hidden |
| + // prototype including own lookups. |
| + // |
| + // Additionally, we need to make sure that we do not cache results |
| + // for objects that require access checks. |
| + if (receiver_obj->IsJSObject()) { |
| + if (!receiver_obj->IsJSGlobalProxy() && |
| + !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { |
| + DisallowHeapAllocation no_allocation; |
| + Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); |
| + Handle<Name> key = Handle<Name>::cast(key_obj); |
| + if (receiver->IsGlobalObject()) { |
| + // Attempt dictionary lookup. |
| + GlobalDictionary* dictionary = receiver->global_dictionary(); |
| + int entry = dictionary->FindEntry(key); |
| + if (entry != GlobalDictionary::kNotFound) { |
| + DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); |
| + PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); |
| + if (cell->property_details().type() == DATA) { |
| + Object* value = cell->value(); |
| + if (!value->IsTheHole()) return Handle<Object>(value, isolate); |
| + // If value is the hole (meaning, absent) do the general lookup. |
| + } |
| + } |
| + } else if (!receiver->HasFastProperties()) { |
| + // Attempt dictionary lookup. |
| + NameDictionary* dictionary = receiver->property_dictionary(); |
| + int entry = dictionary->FindEntry(key); |
| + if ((entry != NameDictionary::kNotFound) && |
| + (dictionary->DetailsAt(entry).type() == DATA)) { |
| + Object* value = dictionary->ValueAt(entry); |
| + return Handle<Object>(value, isolate); |
| + } |
| + } |
| + } else if (key_obj->IsSmi()) { |
| + // JSObject without a name 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 = Handle<JSObject>::cast(receiver_obj); |
| + ElementsKind elements_kind = js_object->GetElementsKind(); |
| + if (IsFastDoubleElementsKind(elements_kind)) { |
| + Handle<Smi> key = Handle<Smi>::cast(key_obj); |
| + if (key->value() >= js_object->elements()->length()) { |
| + if (IsFastHoleyElementsKind(elements_kind)) { |
| + elements_kind = FAST_HOLEY_ELEMENTS; |
| + } else { |
| + elements_kind = FAST_ELEMENTS; |
| + } |
| + RETURN_ON_EXCEPTION( |
| + isolate, TransitionElements(js_object, elements_kind, isolate), |
| + Object); |
| + } |
| + } else { |
| + DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || |
| + !IsFastElementsKind(elements_kind)); |
| + } |
| + } |
| + } else if (receiver_obj->IsString() && key_obj->IsSmi()) { |
| + // Fast case for string indexing using [] with a smi index. |
| + Handle<String> str = Handle<String>::cast(receiver_obj); |
| + int index = Handle<Smi>::cast(key_obj)->value(); |
| + if (index >= 0 && index < str->length()) { |
| + return GetCharAt(str, index); |
| + } |
| } |
| + |
| + // Fall back to GetObjectProperty. |
| + Handle<Object> result; |
| + ASSIGN_RETURN_ON_EXCEPTION( |
|
Toon Verwaest
2015/06/09 11:58:04
If you don't use result you can just return GetObj
conradw
2015/06/09 13:09:27
Done.
|
| + isolate, result, |
| + GetObjectProperty(isolate, receiver_obj, key_obj, strength), |
| + Object); |
| + return result; |
| } |
| @@ -499,122 +608,35 @@ RUNTIME_FUNCTION(Runtime_ObjectSeal) { |
| RUNTIME_FUNCTION(Runtime_GetProperty) { |
| HandleScope scope(isolate); |
| - DCHECK(args.length() == 2); |
| + DCHECK(args.length() == 3); |
| CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); |
| + CONVERT_BOOLEAN_ARG_CHECKED(strength, 2); |
| + |
| Handle<Object> result; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| - isolate, result, Runtime::GetObjectProperty(isolate, object, key)); |
| + isolate, result, |
| + Runtime::GetObjectProperty(isolate, object, key, |
| + static_cast<Strength>(strength))); |
| return *result; |
| } |
| -MUST_USE_RESULT static MaybeHandle<Object> TransitionElements( |
| - Handle<Object> object, ElementsKind to_kind, Isolate* isolate) { |
| - HandleScope scope(isolate); |
| - if (!object->IsJSObject()) { |
| - isolate->ThrowIllegalOperation(); |
| - return MaybeHandle<Object>(); |
| - } |
| - ElementsKind from_kind = |
| - Handle<JSObject>::cast(object)->map()->elements_kind(); |
| - if (Map::IsValidElementsTransition(from_kind, to_kind)) { |
| - JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); |
| - return object; |
| - } |
| - isolate->ThrowIllegalOperation(); |
| - return MaybeHandle<Object>(); |
| -} |
| - |
| - |
| // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. |
| RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { |
| HandleScope scope(isolate); |
| - DCHECK(args.length() == 2); |
| + DCHECK(args.length() == 3); |
| CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); |
| CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); |
| + CONVERT_BOOLEAN_ARG_CHECKED(strength, 2); |
| - // Fast cases for getting named properties of the receiver JSObject |
| - // itself. |
| - // |
| - // The global proxy objects has to be excluded since LookupOwn on |
| - // the global proxy object can return a valid result even though the |
| - // global proxy object never has properties. This is the case |
| - // because the global proxy object forwards everything to its hidden |
| - // prototype including own lookups. |
| - // |
| - // Additionally, we need to make sure that we do not cache results |
| - // for objects that require access checks. |
| - if (receiver_obj->IsJSObject()) { |
| - if (!receiver_obj->IsJSGlobalProxy() && |
| - !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { |
| - DisallowHeapAllocation no_allocation; |
| - Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); |
| - Handle<Name> key = Handle<Name>::cast(key_obj); |
| - if (receiver->IsGlobalObject()) { |
| - // Attempt dictionary lookup. |
| - GlobalDictionary* dictionary = receiver->global_dictionary(); |
| - int entry = dictionary->FindEntry(key); |
| - if (entry != GlobalDictionary::kNotFound) { |
| - DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); |
| - PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); |
| - if (cell->property_details().type() == DATA) { |
| - Object* value = cell->value(); |
| - if (!value->IsTheHole()) return value; |
| - // If value is the hole (meaning, absent) do the general lookup. |
| - } |
| - } |
| - } else if (!receiver->HasFastProperties()) { |
| - // Attempt dictionary lookup. |
| - NameDictionary* dictionary = receiver->property_dictionary(); |
| - int entry = dictionary->FindEntry(key); |
| - if ((entry != NameDictionary::kNotFound) && |
| - (dictionary->DetailsAt(entry).type() == DATA)) { |
| - Object* value = dictionary->ValueAt(entry); |
| - return value; |
| - } |
| - } |
| - } else if (key_obj->IsSmi()) { |
| - // JSObject without a name 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 = Handle<JSObject>::cast(receiver_obj); |
| - ElementsKind elements_kind = js_object->GetElementsKind(); |
| - if (IsFastDoubleElementsKind(elements_kind)) { |
| - Handle<Smi> key = Handle<Smi>::cast(key_obj); |
| - if (key->value() >= js_object->elements()->length()) { |
| - if (IsFastHoleyElementsKind(elements_kind)) { |
| - elements_kind = FAST_HOLEY_ELEMENTS; |
| - } else { |
| - elements_kind = FAST_ELEMENTS; |
| - } |
| - RETURN_FAILURE_ON_EXCEPTION( |
| - isolate, TransitionElements(js_object, elements_kind, isolate)); |
| - } |
| - } else { |
| - DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || |
| - !IsFastElementsKind(elements_kind)); |
| - } |
| - } |
| - } else if (receiver_obj->IsString() && key_obj->IsSmi()) { |
| - // Fast case for string indexing using [] with a smi index. |
| - Handle<String> str = Handle<String>::cast(receiver_obj); |
| - int index = args.smi_at(1); |
| - if (index >= 0 && index < str->length()) { |
| - return *GetCharAt(str, index); |
| - } |
| - } |
| - |
| - // Fall back to GetObjectProperty. |
| Handle<Object> result; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, result, |
| - Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); |
| + Runtime::KeyedGetObjectProperty(isolate, receiver_obj, key_obj, |
| + static_cast<Strength>(strength))); |
| return *result; |
| } |