[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. R=yangguo@chromium.org Review URL: https://codereview.chromium.org/1607943003 Cr-Commit-Position: refs/heads/master@{#33398}
This commit is contained in:
parent
24292e1282
commit
ffa9e82235
@ -2732,6 +2732,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, \
|
||||
|
@ -2559,6 +2559,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,
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user