Commit 059f2fa1 authored by verwaest's avatar verwaest Committed by Commit bot

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}
parent 42ac51c8
......@@ -2994,6 +2994,14 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
native_context()->set_object_function_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
// and the String function has been set up.
Handle<JSFunction> string_function(native_context()->string_function());
......
......@@ -1618,6 +1618,8 @@ BUILTIN(ObjectAssign) {
// 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) {
HandleScope scope(isolate);
Handle<Object> prototype = args.atOrUndefined(isolate, 1);
......@@ -1633,7 +1635,26 @@ BUILTIN(ObjectCreate) {
Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
isolate);
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.
......
......@@ -217,6 +217,7 @@ enum BindingFlags {
V(NORMALIZED_MAP_CACHE_INDEX, Object, normalized_map_cache) \
V(NUMBER_FUNCTION_INDEX, JSFunction, number_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(OPAQUE_REFERENCE_FUNCTION_INDEX, JSFunction, opaque_reference_function) \
V(PROXY_CALLABLE_MAP_INDEX, Map, proxy_callable_map) \
......
......@@ -5486,7 +5486,24 @@ ACCESSORS(AccessorInfo, data, Object, kDataOffset)
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, object_create_map, Object, kObjectCreateMap)
SMI_ACCESSORS(PrototypeInfo, registry_slot, kRegistrySlotOffset)
ACCESSORS(PrototypeInfo, validity_cell, Object, kValidityCellOffset)
SMI_ACCESSORS(PrototypeInfo, bit_field, kBitFieldOffset)
......
......@@ -6304,6 +6304,13 @@ class PrototypeInfo : public Struct {
// [prototype_users]: WeakFixedArray containing maps using this prototype,
// or Smi(0) if uninitialized.
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
// is stored. Returns UNREGISTERED if this prototype has not been registered.
inline int registry_slot() const;
......@@ -6330,13 +6337,16 @@ class PrototypeInfo : public Struct {
static const int kPrototypeUsersOffset = HeapObject::kHeaderSize;
static const int kRegistrySlotOffset = kPrototypeUsersOffset + 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;
// Bit field usage.
static const int kShouldBeFastBit = 0;
private:
DECL_ACCESSORS(object_create_map, Object)
DISALLOW_IMPLICIT_CONSTRUCTORS(PrototypeInfo);
};
......
......@@ -80,7 +80,7 @@ bytecodes: [
/* 15 S> */ B(LdrUndefined), R(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(3),
B(Star), R(1),
B(CallJSRuntime), U8(128), R(0), U8(2),
B(CallJSRuntime), U8(129), R(0), U8(2),
/* 44 S> */ B(Return),
]
constant pool: [
......
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