Commit 8e8bd866 authored by bmeurer's avatar bmeurer Committed by Commit bot

[runtime] Introduce maps for the likely cases of FromPropertyDescriptor.

This change improves performance for the common case of
Object.getOwnPropertyDescriptor by up 3x-4x, where we just
return a property descriptor object for a regular data or
accessor property.

CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_chromium_rel_ng
R=yangguo@chromium.org

Committed: https://crrev.com/ffa9e82235b20c523ebb1151c6196bc6232296b9
Cr-Commit-Position: refs/heads/master@{#33398}

Review URL: https://codereview.chromium.org/1607943003

Cr-Commit-Position: refs/heads/master@{#33415}
parent 0b3066b8
......@@ -2728,6 +2728,89 @@ bool Genesis::InstallNatives(ContextType context_type) {
InstallBuiltinFunctionIds();
// Create a map for accessor property descriptors (a variant of JSObject
// that predefines four properties get, set, configurable and enumerable).
{
// AccessorPropertyDescriptor initial map.
Handle<Map> map =
factory()->NewMap(JS_OBJECT_TYPE, JSAccessorPropertyDescriptor::kSize);
// Create the descriptor array for the property descriptor object.
Map::EnsureDescriptorSlack(map, 4);
{ // get
DataDescriptor d(factory()->get_string(),
JSAccessorPropertyDescriptor::kGetIndex, NONE,
Representation::Tagged());
map->AppendDescriptor(&d);
}
{ // set
DataDescriptor d(factory()->set_string(),
JSAccessorPropertyDescriptor::kSetIndex, NONE,
Representation::Tagged());
map->AppendDescriptor(&d);
}
{ // enumerable
DataDescriptor d(factory()->enumerable_string(),
JSAccessorPropertyDescriptor::kEnumerableIndex, NONE,
Representation::Tagged());
map->AppendDescriptor(&d);
}
{ // configurable
DataDescriptor d(factory()->configurable_string(),
JSAccessorPropertyDescriptor::kConfigurableIndex, NONE,
Representation::Tagged());
map->AppendDescriptor(&d);
}
Map::SetPrototype(map, isolate()->initial_object_prototype());
map->SetInObjectProperties(4);
map->set_unused_property_fields(0);
native_context()->set_accessor_property_descriptor_map(*map);
}
// Create a map for data property descriptors (a variant of JSObject
// that predefines four properties value, writable, configurable and
// enumerable).
{
// DataPropertyDescriptor initial map.
Handle<Map> map =
factory()->NewMap(JS_OBJECT_TYPE, JSDataPropertyDescriptor::kSize);
// Create the descriptor array for the property descriptor object.
Map::EnsureDescriptorSlack(map, 4);
{ // value
DataDescriptor d(factory()->value_string(),
JSDataPropertyDescriptor::kValueIndex, NONE,
Representation::Tagged());
map->AppendDescriptor(&d);
}
{ // writable
DataDescriptor d(factory()->writable_string(),
JSDataPropertyDescriptor::kWritableIndex, NONE,
Representation::Tagged());
map->AppendDescriptor(&d);
}
{ // enumerable
DataDescriptor d(factory()->enumerable_string(),
JSDataPropertyDescriptor::kEnumerableIndex, NONE,
Representation::Tagged());
map->AppendDescriptor(&d);
}
{ // configurable
DataDescriptor d(factory()->configurable_string(),
JSDataPropertyDescriptor::kConfigurableIndex, NONE,
Representation::Tagged());
map->AppendDescriptor(&d);
}
Map::SetPrototype(map, isolate()->initial_object_prototype());
map->SetInObjectProperties(4);
map->set_unused_property_fields(0);
native_context()->set_data_property_descriptor_map(*map);
}
// Create a constructor for RegExp results (a variant of Array that
// predefines the two properties index and match).
{
......
......@@ -155,6 +155,8 @@ enum BindingFlags {
V(GLOBAL_PROXY_INDEX, JSObject, global_proxy_object) \
V(EMBEDDER_DATA_INDEX, FixedArray, embedder_data) \
/* Below is alpha-sorted */ \
V(ACCESSOR_PROPERTY_DESCRIPTOR_MAP_INDEX, Map, \
accessor_property_descriptor_map) \
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
V(ARRAY_BUFFER_FUN_INDEX, JSFunction, array_buffer_fun) \
V(ARRAY_BUFFER_MAP_INDEX, Map, array_buffer_map) \
......@@ -171,6 +173,7 @@ enum BindingFlags {
call_as_constructor_delegate) \
V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
V(DATA_PROPERTY_DESCRIPTOR_MAP_INDEX, Map, data_property_descriptor_map) \
V(DATA_VIEW_FUN_INDEX, JSFunction, data_view_fun) \
V(DATE_FUNCTION_INDEX, JSFunction, date_function) \
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
......
......@@ -2562,6 +2562,52 @@ class JSObject: public JSReceiver {
};
// JSAccessorPropertyDescriptor is just a JSObject with a specific initial
// map. This initial map adds in-object properties for "get", "set",
// "enumerable" and "configurable" properties, as assigned by the
// FromPropertyDescriptor function for regular accessor properties.
class JSAccessorPropertyDescriptor: public JSObject {
public:
// Offsets of object fields.
static const int kGetOffset = JSObject::kHeaderSize;
static const int kSetOffset = kGetOffset + kPointerSize;
static const int kEnumerableOffset = kSetOffset + kPointerSize;
static const int kConfigurableOffset = kEnumerableOffset + kPointerSize;
static const int kSize = kConfigurableOffset + kPointerSize;
// Indices of in-object properties.
static const int kGetIndex = 0;
static const int kSetIndex = 1;
static const int kEnumerableIndex = 2;
static const int kConfigurableIndex = 3;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSAccessorPropertyDescriptor);
};
// JSDataPropertyDescriptor is just a JSObject with a specific initial map.
// This initial map adds in-object properties for "value", "writable",
// "enumerable" and "configurable" properties, as assigned by the
// FromPropertyDescriptor function for regular data properties.
class JSDataPropertyDescriptor: public JSObject {
public:
// Offsets of object fields.
static const int kValueOffset = JSObject::kHeaderSize;
static const int kWritableOffset = kValueOffset + kPointerSize;
static const int kEnumerableOffset = kWritableOffset + kPointerSize;
static const int kConfigurableOffset = kEnumerableOffset + kPointerSize;
static const int kSize = kConfigurableOffset + kPointerSize;
// Indices of in-object properties.
static const int kValueIndex = 0;
static const int kWritableIndex = 1;
static const int kEnumerableIndex = 2;
static const int kConfigurableIndex = 3;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSDataPropertyDescriptor);
};
// Common superclass for FixedArrays that allow implementations to share
// common accessors and some code paths.
class FixedArrayBase: public HeapObject {
......
......@@ -13,6 +13,8 @@
namespace v8 {
namespace internal {
namespace {
// Helper function for ToPropertyDescriptor. Comments describe steps for
// "enumerable", other properties are handled the same way.
// Returns false if an exception was thrown.
......@@ -101,19 +103,51 @@ bool ToPropertyDescriptorFastPath(Isolate* isolate, Handle<Object> obj,
}
static void CreateDataProperty(Isolate* isolate, Handle<JSObject> object,
Handle<String> name, Handle<Object> value) {
void CreateDataProperty(Isolate* isolate, Handle<JSObject> object,
Handle<String> name, Handle<Object> value) {
LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
Maybe<bool> result = JSObject::CreateDataProperty(&it, value);
CHECK(result.IsJust() && result.FromJust());
}
} // namespace
// ES6 6.2.4.4 "FromPropertyDescriptor"
Handle<Object> PropertyDescriptor::ToObject(Isolate* isolate) {
DCHECK(!(PropertyDescriptor::IsAccessorDescriptor(this) &&
PropertyDescriptor::IsDataDescriptor(this)));
Factory* factory = isolate->factory();
if (IsRegularAccessorProperty()) {
// Fast case for regular accessor properties.
Handle<JSObject> result = factory->NewJSObjectFromMap(
isolate->accessor_property_descriptor_map());
result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kGetIndex,
*get());
result->InObjectPropertyAtPut(JSAccessorPropertyDescriptor::kSetIndex,
*set());
result->InObjectPropertyAtPut(
JSAccessorPropertyDescriptor::kEnumerableIndex,
isolate->heap()->ToBoolean(enumerable()));
result->InObjectPropertyAtPut(
JSAccessorPropertyDescriptor::kConfigurableIndex,
isolate->heap()->ToBoolean(configurable()));
return result;
}
if (IsRegularDataProperty()) {
// Fast case for regular data properties.
Handle<JSObject> result =
factory->NewJSObjectFromMap(isolate->data_property_descriptor_map());
result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kValueIndex,
*value());
result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kWritableIndex,
isolate->heap()->ToBoolean(writable()));
result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kEnumerableIndex,
isolate->heap()->ToBoolean(enumerable()));
result->InObjectPropertyAtPut(JSDataPropertyDescriptor::kConfigurableIndex,
isolate->heap()->ToBoolean(configurable()));
return result;
}
Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
if (has_value()) {
CreateDataProperty(isolate, result, factory->value_string(), value());
......
......@@ -57,6 +57,16 @@ class PropertyDescriptor {
!has_value() && !has_get() && !has_set();
}
bool IsRegularAccessorProperty() const {
return has_configurable() && has_enumerable() && !has_value() &&
!has_writable() && has_get() && has_set();
}
bool IsRegularDataProperty() const {
return has_configurable() && has_enumerable() && has_value() &&
has_writable() && !has_get() && !has_set();
}
bool enumerable() const { return enumerable_; }
void set_enumerable(bool enumerable) {
enumerable_ = enumerable;
......
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