| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index a1f34cb95d7e86f02ce7d95da679b85a2ede8e11..4164df55d8db6723e2177182dfaa0ce26800960e 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -1026,7 +1026,7 @@ Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate,
|
| FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
|
| // Check the receiver.
|
| for (PrototypeIterator iter(isolate, JSObject::cast(receiver),
|
| - PrototypeIterator::START_AT_RECEIVER,
|
| + kStartAtReceiver,
|
| PrototypeIterator::END_AT_NON_HIDDEN);
|
| !iter.IsAtEnd(); iter.Advance()) {
|
| if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent();
|
| @@ -1484,7 +1484,7 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
|
| Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate,
|
| Handle<JSReceiver> object,
|
| Handle<Object> proto) {
|
| - PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER);
|
| + PrototypeIterator iter(isolate, object, kStartAtReceiver);
|
| while (true) {
|
| if (!iter.AdvanceFollowingProxies()) return Nothing<bool>();
|
| if (iter.IsAtEnd()) return Just(false);
|
| @@ -11862,6 +11862,26 @@ static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) {
|
| return false;
|
| }
|
|
|
| +// static
|
| +void JSObject::MakePrototypesFast(Handle<Object> receiver,
|
| + WhereToStart where_to_start,
|
| + Isolate* isolate) {
|
| + if (!receiver->IsJSReceiver()) return;
|
| + for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver),
|
| + where_to_start);
|
| + !iter.IsAtEnd(); iter.Advance()) {
|
| + Handle<Object> current = PrototypeIterator::GetCurrent(iter);
|
| + if (!current->IsJSObject()) return;
|
| + Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
|
| + Map* current_map = current_obj->map();
|
| + if (current_map->is_prototype_map() &&
|
| + !current_map->should_be_fast_prototype_map()) {
|
| + Handle<Map> map(current_map);
|
| + Map::SetShouldBeFastPrototypeMap(map, true, isolate);
|
| + JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE);
|
| + }
|
| + }
|
| +}
|
|
|
| // static
|
| void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
|
| @@ -11873,10 +11893,12 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
|
| "NormalizeAsPrototype");
|
| }
|
| Handle<Map> previous_map(object->map());
|
| - if (!object->HasFastProperties()) {
|
| - JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
|
| - }
|
| - if (!object->map()->is_prototype_map()) {
|
| + if (object->map()->is_prototype_map()) {
|
| + if (object->map()->should_be_fast_prototype_map() &&
|
| + !object->HasFastProperties()) {
|
| + JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
|
| + }
|
| + } else {
|
| if (object->map() == *previous_map) {
|
| Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
|
| JSObject::MigrateToMap(object, new_map);
|
| @@ -11904,6 +11926,7 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
|
| // static
|
| void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
|
| if (!object->map()->is_prototype_map()) return;
|
| + if (!object->map()->should_be_fast_prototype_map()) return;
|
| OptimizeAsPrototype(object, FAST_PROTOTYPE);
|
| }
|
|
|
| @@ -12045,6 +12068,15 @@ Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<Map> prototype_map,
|
| return proto_info;
|
| }
|
|
|
| +// static
|
| +void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value,
|
| + Isolate* isolate) {
|
| + if (value == false && !map->prototype_info()->IsPrototypeInfo()) {
|
| + // "False" is the implicit default value, so there's nothing to do.
|
| + return;
|
| + }
|
| + GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value);
|
| +}
|
|
|
| // static
|
| Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
|
| @@ -13041,9 +13073,8 @@ void JSFunction::CalculateInstanceSizeForDerivedClass(
|
| int* instance_size, int* in_object_properties) {
|
| Isolate* isolate = GetIsolate();
|
| int expected_nof_properties = 0;
|
| - for (PrototypeIterator iter(isolate, this,
|
| - PrototypeIterator::START_AT_RECEIVER);
|
| - !iter.IsAtEnd(); iter.Advance()) {
|
| + for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd();
|
| + iter.Advance()) {
|
| JSReceiver* current = iter.GetCurrent<JSReceiver>();
|
| if (!current->IsJSFunction()) break;
|
| JSFunction* func = JSFunction::cast(current);
|
| @@ -14867,8 +14898,7 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
|
| if (from_javascript) {
|
| // Find the first object in the chain whose prototype object is not
|
| // hidden.
|
| - PrototypeIterator iter(isolate, real_receiver,
|
| - PrototypeIterator::START_AT_PROTOTYPE,
|
| + PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype,
|
| PrototypeIterator::END_AT_NON_HIDDEN);
|
| while (!iter.IsAtEnd()) {
|
| // Casting to JSObject is fine because hidden prototypes are never
|
| @@ -14901,7 +14931,7 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object,
|
| // new prototype chain.
|
| if (value->IsJSReceiver()) {
|
| for (PrototypeIterator iter(isolate, JSReceiver::cast(*value),
|
| - PrototypeIterator::START_AT_RECEIVER);
|
| + kStartAtReceiver);
|
| !iter.IsAtEnd(); iter.Advance()) {
|
| if (iter.GetCurrent<JSReceiver>() == *object) {
|
| // Cycle detected.
|
|
|