Commit 5f27e5c7 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[runtime] Merge %KeyedGetProperty into %GetProperty.

As noticed by jkummerow@ there's probably not really a point in
keeping two separate runtime functions that perform the same
operation, but one has a different fast-path (which is not
available to the other). So %KeyedGetProperty is now effectively
%GetProperty and used consistently as fallback from both the ICs
as well as other callers like the GetProperty builtin.

Bug: v8:8015
Change-Id: Ib46b13da739229e2eb820ecf87923ac99c6971d3
Reviewed-on: https://chromium-review.googlesource.com/1199105
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55547}
parent e7ca2b7c
...@@ -28,7 +28,7 @@ TF_BUILTIN(KeyedLoadIC_Slow, CodeStubAssembler) { ...@@ -28,7 +28,7 @@ TF_BUILTIN(KeyedLoadIC_Slow, CodeStubAssembler) {
Node* name = Parameter(Descriptor::kName); Node* name = Parameter(Descriptor::kName);
Node* context = Parameter(Descriptor::kContext); Node* context = Parameter(Descriptor::kContext);
TailCallRuntime(Runtime::kKeyedGetProperty, context, receiver, name); TailCallRuntime(Runtime::kGetProperty, context, receiver, name);
} }
void Builtins::Generate_KeyedStoreIC_Megamorphic( void Builtins::Generate_KeyedStoreIC_Megamorphic(
......
...@@ -2810,7 +2810,7 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { ...@@ -2810,7 +2810,7 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
Comment("KeyedLoadGeneric_slow"); Comment("KeyedLoadGeneric_slow");
IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1); IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1);
// TODO(jkummerow): Should we use the GetProperty TF stub instead? // TODO(jkummerow): Should we use the GetProperty TF stub instead?
TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver, TailCallRuntime(Runtime::kGetProperty, p->context, p->receiver,
var_unique.value()); var_unique.value());
} }
} }
......
...@@ -49,95 +49,6 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, ...@@ -49,95 +49,6 @@ MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
return result; return result;
} }
static MaybeHandle<Object> KeyedGetObjectProperty(Isolate* isolate,
Handle<Object> receiver_obj,
Handle<Object> key_obj) {
// 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.
// Convert string-index keys to their number variant to avoid internalization
// below; and speed up subsequent conversion to index.
uint32_t index;
if (key_obj->IsString() && String::cast(*key_obj)->AsArrayIndex(&index)) {
key_obj = isolate->factory()->NewNumberFromUint(index);
}
if (receiver_obj->IsJSObject()) {
if (!receiver_obj->IsJSGlobalProxy() &&
!receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) {
Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
Handle<Name> key = Handle<Name>::cast(key_obj);
key_obj = key = isolate->factory()->InternalizeName(key);
DisallowHeapAllocation no_allocation;
if (receiver->IsJSGlobalObject()) {
// Attempt dictionary lookup.
GlobalDictionary* dictionary =
JSGlobalObject::cast(*receiver)->global_dictionary();
int entry = dictionary->FindEntry(isolate, key);
if (entry != GlobalDictionary::kNotFound) {
PropertyCell* cell = dictionary->CellAt(entry);
if (cell->property_details().kind() == kData) {
Object* value = cell->value();
if (!value->IsTheHole(isolate)) {
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(isolate, key);
if ((entry != NameDictionary::kNotFound) &&
(dictionary->DetailsAt(entry).kind() == kData)) {
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 PACKED_DOUBLE_ELEMENTS.
Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
ElementsKind elements_kind = js_object->GetElementsKind();
if (IsDoubleElementsKind(elements_kind)) {
if (Smi::ToInt(*key_obj) >= js_object->elements()->length()) {
elements_kind = IsHoleyElementsKind(elements_kind) ? HOLEY_ELEMENTS
: PACKED_ELEMENTS;
JSObject::TransitionElementsKind(js_object, elements_kind);
}
} else {
DCHECK(IsSmiOrObjectElementsKind(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()) {
Factory* factory = isolate->factory();
return factory->LookupSingleCharacterStringFromCode(
String::Flatten(isolate, str)->Get(index));
}
}
// Fall back to GetObjectProperty.
return Runtime::GetObjectProperty(isolate, receiver_obj, key_obj);
}
namespace { namespace {
bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver, bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
...@@ -553,24 +464,91 @@ RUNTIME_FUNCTION(Runtime_ObjectEntriesSkipFastPath) { ...@@ -553,24 +464,91 @@ RUNTIME_FUNCTION(Runtime_ObjectEntriesSkipFastPath) {
RUNTIME_FUNCTION(Runtime_GetProperty) { RUNTIME_FUNCTION(Runtime_GetProperty) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); // Fast cases for getting named properties of the receiver JSObject
CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); // itself.
//
RETURN_RESULT_OR_FAILURE(isolate, // The global proxy objects has to be excluded since LookupOwn on
Runtime::GetObjectProperty(isolate, object, key)); // 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.
// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. // Convert string-index keys to their number variant to avoid internalization
RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { // below; and speed up subsequent conversion to index.
HandleScope scope(isolate); uint32_t index;
DCHECK_EQ(2, args.length()); if (key_obj->IsString() && String::cast(*key_obj)->AsArrayIndex(&index)) {
key_obj = isolate->factory()->NewNumberFromUint(index);
}
if (receiver_obj->IsJSObject()) {
if (!receiver_obj->IsJSGlobalProxy() &&
!receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) {
Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
Handle<Name> key = Handle<Name>::cast(key_obj);
key_obj = key = isolate->factory()->InternalizeName(key);
CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); DisallowHeapAllocation no_allocation;
CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); if (receiver->IsJSGlobalObject()) {
// Attempt dictionary lookup.
GlobalDictionary* dictionary =
JSGlobalObject::cast(*receiver)->global_dictionary();
int entry = dictionary->FindEntry(isolate, key);
if (entry != GlobalDictionary::kNotFound) {
PropertyCell* cell = dictionary->CellAt(entry);
if (cell->property_details().kind() == kData) {
Object* value = cell->value();
if (!value->IsTheHole(isolate)) 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(isolate, key);
if ((entry != NameDictionary::kNotFound) &&
(dictionary->DetailsAt(entry).kind() == kData)) {
return dictionary->ValueAt(entry);
}
}
} 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 PACKED_DOUBLE_ELEMENTS.
Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
ElementsKind elements_kind = js_object->GetElementsKind();
if (IsDoubleElementsKind(elements_kind)) {
if (Smi::ToInt(*key_obj) >= js_object->elements()->length()) {
elements_kind = IsHoleyElementsKind(elements_kind) ? HOLEY_ELEMENTS
: PACKED_ELEMENTS;
JSObject::TransitionElementsKind(js_object, elements_kind);
}
} else {
DCHECK(IsSmiOrObjectElementsKind(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()) {
Factory* factory = isolate->factory();
return *factory->LookupSingleCharacterStringFromCode(
String::Flatten(isolate, str)->Get(index));
}
}
// Fall back to GetObjectProperty.
RETURN_RESULT_OR_FAILURE( RETURN_RESULT_OR_FAILURE(
isolate, KeyedGetObjectProperty(isolate, receiver_obj, key_obj)); isolate, Runtime::GetObjectProperty(isolate, receiver_obj, key_obj));
} }
RUNTIME_FUNCTION(Runtime_AddNamedProperty) { RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
......
...@@ -329,7 +329,6 @@ namespace internal { ...@@ -329,7 +329,6 @@ namespace internal {
F(HasProperty, 2, 1) \ F(HasProperty, 2, 1) \
F(InternalSetPrototype, 2, 1) \ F(InternalSetPrototype, 2, 1) \
F(IsJSReceiver, 1, 1) \ F(IsJSReceiver, 1, 1) \
F(KeyedGetProperty, 2, 1) \
F(NewObject, 2, 1) \ F(NewObject, 2, 1) \
F(ObjectCreate, 2, 1) \ F(ObjectCreate, 2, 1) \
F(ObjectEntries, 1, 1) \ F(ObjectEntries, 1, 1) \
......
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