Cache Object.create maps on the passed prototype's PrototypeInfo

BUG=chromium:603144

Review-Url: https://codereview.chromium.org/2083353002
Cr-Commit-Position: refs/heads/master@{#37214}
This commit is contained in:
verwaest 2016-06-23 05:16:35 -07:00 committed by Commit bot
parent 42ac51c82e
commit 059f2fa101
6 changed files with 60 additions and 3 deletions

View File

@ -2994,6 +2994,14 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
native_context()->set_object_function_prototype_map( native_context()->set_object_function_prototype_map(
HeapObject::cast(object_function->initial_map()->prototype())->map()); HeapObject::cast(object_function->initial_map()->prototype())->map());
// Set up the map for Object.create(null) instances.
Handle<Map> object_with_null_prototype_map =
Map::CopyInitialMap(handle(object_function->initial_map(), isolate()));
Map::SetPrototype(object_with_null_prototype_map,
isolate()->factory()->null_value());
native_context()->set_object_with_null_prototype_map(
*object_with_null_prototype_map);
// Store the map for the %StringPrototype% after the natives has been compiled // Store the map for the %StringPrototype% after the natives has been compiled
// and the String function has been set up. // and the String function has been set up.
Handle<JSFunction> string_function(native_context()->string_function()); Handle<JSFunction> string_function(native_context()->string_function());

View File

@ -1618,6 +1618,8 @@ BUILTIN(ObjectAssign) {
// ES6 section 19.1.2.2 Object.create ( O [ , Properties ] ) // ES6 section 19.1.2.2 Object.create ( O [ , Properties ] )
// TODO(verwaest): Support the common cases with precached map directly in
// an Object.create stub.
BUILTIN(ObjectCreate) { BUILTIN(ObjectCreate) {
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<Object> prototype = args.atOrUndefined(isolate, 1); Handle<Object> prototype = args.atOrUndefined(isolate, 1);
@ -1633,7 +1635,26 @@ BUILTIN(ObjectCreate) {
Handle<Map> map(isolate->native_context()->object_function()->initial_map(), Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
isolate); isolate);
if (map->prototype() != *prototype) { if (map->prototype() != *prototype) {
map = Map::TransitionToPrototype(map, prototype, FAST_PROTOTYPE); if (prototype->IsNull(isolate)) {
map = isolate->object_with_null_prototype_map();
} else if (prototype->IsJSObject()) {
Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
if (!js_prototype->map()->is_prototype_map()) {
JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE);
}
Handle<PrototypeInfo> info =
Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
// TODO(verwaest): Use inobject slack tracking for this map.
if (info->HasObjectCreateMap()) {
map = handle(info->ObjectCreateMap(), isolate);
} else {
map = Map::CopyInitialMap(map);
Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
PrototypeInfo::SetObjectCreateMap(info, map);
}
} else {
map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE);
}
} }
// Actually allocate the object. // Actually allocate the object.

View File

@ -217,6 +217,7 @@ enum BindingFlags {
V(NORMALIZED_MAP_CACHE_INDEX, Object, normalized_map_cache) \ V(NORMALIZED_MAP_CACHE_INDEX, Object, normalized_map_cache) \
V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \ V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \
V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \ V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
V(OBJECT_WITH_NULL_PROTOTYPE_MAP, Map, object_with_null_prototype_map) \
V(OBJECT_FUNCTION_PROTOTYPE_MAP_INDEX, Map, object_function_prototype_map) \ V(OBJECT_FUNCTION_PROTOTYPE_MAP_INDEX, Map, object_function_prototype_map) \
V(OPAQUE_REFERENCE_FUNCTION_INDEX, JSFunction, opaque_reference_function) \ V(OPAQUE_REFERENCE_FUNCTION_INDEX, JSFunction, opaque_reference_function) \
V(PROXY_CALLABLE_MAP_INDEX, Map, proxy_callable_map) \ V(PROXY_CALLABLE_MAP_INDEX, Map, proxy_callable_map) \

View File

@ -5486,7 +5486,24 @@ ACCESSORS(AccessorInfo, data, Object, kDataOffset)
ACCESSORS(Box, value, Object, kValueOffset) ACCESSORS(Box, value, Object, kValueOffset)
Map* PrototypeInfo::ObjectCreateMap() {
return Map::cast(WeakCell::cast(object_create_map())->value());
}
// static
void PrototypeInfo::SetObjectCreateMap(Handle<PrototypeInfo> info,
Handle<Map> map) {
Handle<WeakCell> cell = Map::WeakCellForMap(map);
info->set_object_create_map(*cell);
}
bool PrototypeInfo::HasObjectCreateMap() {
Object* cache = object_create_map();
return cache->IsWeakCell() && !WeakCell::cast(cache)->cleared();
}
ACCESSORS(PrototypeInfo, prototype_users, Object, kPrototypeUsersOffset) ACCESSORS(PrototypeInfo, prototype_users, Object, kPrototypeUsersOffset)
ACCESSORS(PrototypeInfo, object_create_map, Object, kObjectCreateMap)
SMI_ACCESSORS(PrototypeInfo, registry_slot, kRegistrySlotOffset) SMI_ACCESSORS(PrototypeInfo, registry_slot, kRegistrySlotOffset)
ACCESSORS(PrototypeInfo, validity_cell, Object, kValidityCellOffset) ACCESSORS(PrototypeInfo, validity_cell, Object, kValidityCellOffset)
SMI_ACCESSORS(PrototypeInfo, bit_field, kBitFieldOffset) SMI_ACCESSORS(PrototypeInfo, bit_field, kBitFieldOffset)

View File

@ -6304,6 +6304,13 @@ class PrototypeInfo : public Struct {
// [prototype_users]: WeakFixedArray containing maps using this prototype, // [prototype_users]: WeakFixedArray containing maps using this prototype,
// or Smi(0) if uninitialized. // or Smi(0) if uninitialized.
DECL_ACCESSORS(prototype_users, Object) DECL_ACCESSORS(prototype_users, Object)
// [object_create_map]: A field caching the map for Object.create(prototype).
static inline void SetObjectCreateMap(Handle<PrototypeInfo> info,
Handle<Map> map);
inline Map* ObjectCreateMap();
inline bool HasObjectCreateMap();
// [registry_slot]: Slot in prototype's user registry where this user // [registry_slot]: Slot in prototype's user registry where this user
// is stored. Returns UNREGISTERED if this prototype has not been registered. // is stored. Returns UNREGISTERED if this prototype has not been registered.
inline int registry_slot() const; inline int registry_slot() const;
@ -6330,13 +6337,16 @@ class PrototypeInfo : public Struct {
static const int kPrototypeUsersOffset = HeapObject::kHeaderSize; static const int kPrototypeUsersOffset = HeapObject::kHeaderSize;
static const int kRegistrySlotOffset = kPrototypeUsersOffset + kPointerSize; static const int kRegistrySlotOffset = kPrototypeUsersOffset + kPointerSize;
static const int kValidityCellOffset = kRegistrySlotOffset + kPointerSize; static const int kValidityCellOffset = kRegistrySlotOffset + kPointerSize;
static const int kBitFieldOffset = kValidityCellOffset + kPointerSize; static const int kObjectCreateMap = kValidityCellOffset + kPointerSize;
static const int kBitFieldOffset = kObjectCreateMap + kPointerSize;
static const int kSize = kBitFieldOffset + kPointerSize; static const int kSize = kBitFieldOffset + kPointerSize;
// Bit field usage. // Bit field usage.
static const int kShouldBeFastBit = 0; static const int kShouldBeFastBit = 0;
private: private:
DECL_ACCESSORS(object_create_map, Object)
DISALLOW_IMPLICIT_CONSTRUCTORS(PrototypeInfo); DISALLOW_IMPLICIT_CONSTRUCTORS(PrototypeInfo);
}; };

View File

@ -80,7 +80,7 @@ bytecodes: [
/* 15 S> */ B(LdrUndefined), R(0), /* 15 S> */ B(LdrUndefined), R(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(3), B(CreateArrayLiteral), U8(0), U8(0), U8(3),
B(Star), R(1), B(Star), R(1),
B(CallJSRuntime), U8(128), R(0), U8(2), B(CallJSRuntime), U8(129), R(0), U8(2),
/* 44 S> */ B(Return), /* 44 S> */ B(Return),
] ]
constant pool: [ constant pool: [