Index: src/isolate.cc |
diff --git a/src/isolate.cc b/src/isolate.cc |
index 9cee8db2ba79d92adb820c0af6800f66a58c799e..cc009c0fe83fbada12cb9be09b13a79947c03be8 100644 |
--- a/src/isolate.cc |
+++ b/src/isolate.cc |
@@ -2482,6 +2482,64 @@ bool Isolate::use_crankshaft() const { |
CpuFeatures::SupportsCrankshaft(); |
} |
+Context* Isolate::ContextForArrayOrObjectPrototype(Handle<JSObject> object) { |
+ Object* context = heap()->native_contexts_list(); |
+ while (!context->IsUndefined()) { |
+ Context* current_context = Context::cast(context); |
+ if (current_context->initial_object_prototype() == *object || |
+ current_context->initial_array_prototype() == *object) { |
+ return current_context; |
+ } |
+ context = current_context->get(Context::NEXT_CONTEXT_LINK); |
+ } |
+ return NULL; |
+} |
+ |
+bool Isolate::IsArrayIsConcatSpreadableSet() { |
+ PropertyCell* is_concat_spreadable_cell = |
+ heap()->array_is_concat_spreadable_protector(); |
+ bool is_concat_spreadable_set = |
+ is_concat_spreadable_cell->value()->IsSmi() && |
+ Smi::cast(is_concat_spreadable_cell->value())->value() == |
+ kArrayIsConcatSpreadableProtectorInvalid; |
+#ifdef DEBUG |
+ Map* root_array_map = get_initial_js_array_map(GetInitialFastElementsKind()); |
+ if (root_array_map == NULL) { |
+ // Ignore the value of is_concat_spreadable during bootstrap. |
+ return is_concat_spreadable_set; |
+ } |
+ Handle<Object> array_prototype(array_function()->prototype(), this); |
+ Handle<Symbol> key = factory()->is_concat_spreadable_symbol(); |
+ Handle<Object> value; |
+ LookupIterator it(array_prototype, key); |
+ if (it.IsFound() && it.state() != LookupIterator::JSPROXY) { |
+ MaybeHandle<Object> maybe_value = Object::GetProperty(&it); |
+ if (maybe_value.ToHandle(&value) && !value->IsUndefined()) { |
+ // TODO(cbruni): Currently we do not revert if we unset the |
+ // @@isConcatSpreadable property on Array.prototype or Object.prototype |
+ // hence the reverse implication doesn't hold. |
+ DCHECK(is_concat_spreadable_set); |
+ return true; |
+ } |
+ } |
+#endif // DEBUG |
+ return is_concat_spreadable_set; |
+} |
+ |
+void Isolate::UpdateArrayIsConcatSpreadableProtectorOnAddProperty( |
+ Handle<JSObject> object, Handle<Name> name) { |
+ // The invalidate the is_concat_spreadable_protector invalidation is a one-way |
+ // action. |
+ if (IsArrayIsConcatSpreadableSet()) return; |
+ if (!object->map()->is_prototype_map()) return; |
+ Handle<Name> key = factory()->is_concat_spreadable_symbol(); |
+ if (!Name::Equals(name, key)) return; |
+ Context* context = ContextForArrayOrObjectPrototype(object); |
+ if (context == NULL) return; |
+ PropertyCell::SetValueWithInvalidation( |
+ factory()->array_is_concat_spreadable_protector(), |
+ handle(Smi::FromInt(kArrayProtectorInvalid), this)); |
+} |
bool Isolate::IsFastArrayConstructorPrototypeChainIntact() { |
PropertyCell* no_elements_cell = heap()->array_protector(); |
@@ -2571,38 +2629,27 @@ void Isolate::InvalidateArraySpeciesProtector() { |
void Isolate::UpdateArrayProtectorOnSetElement(Handle<JSObject> object) { |
DisallowHeapAllocation no_gc; |
- if (IsFastArrayConstructorPrototypeChainIntact() && |
- object->map()->is_prototype_map()) { |
- Object* context = heap()->native_contexts_list(); |
- while (!context->IsUndefined()) { |
- Context* current_context = Context::cast(context); |
- if (current_context->get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX) == |
- *object || |
- current_context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX) == |
- *object) { |
- CountUsage(v8::Isolate::UseCounterFeature::kArrayProtectorDirtied); |
- PropertyCell::SetValueWithInvalidation( |
- factory()->array_protector(), |
- handle(Smi::FromInt(kArrayProtectorInvalid), this)); |
- break; |
- } |
- context = current_context->get(Context::NEXT_CONTEXT_LINK); |
- } |
- } |
+ if (!IsFastArrayConstructorPrototypeChainIntact()) return; |
+ if (!object->map()->is_prototype_map()) return; |
+ Context* context = ContextForArrayOrObjectPrototype(object); |
+ if (context == NULL) return; |
+ PropertyCell::SetValueWithInvalidation( |
+ factory()->array_protector(), |
+ handle(Smi::FromInt(kArrayProtectorInvalid), this)); |
} |
bool Isolate::IsAnyInitialArrayPrototype(Handle<JSArray> array) { |
- if (array->map()->is_prototype_map()) { |
- Object* context = heap()->native_contexts_list(); |
- while (!context->IsUndefined()) { |
- Context* current_context = Context::cast(context); |
- if (current_context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX) == |
- *array) { |
- return true; |
- } |
- context = current_context->get(Context::NEXT_CONTEXT_LINK); |
+ DisallowHeapAllocation no_gc; |
+ JSArray* raw_array = *array; |
+ if (!raw_array->map()->is_prototype_map()) return false; |
+ Object* context = heap()->native_contexts_list(); |
+ while (!context->IsUndefined()) { |
+ Context* current_context = Context::cast(context); |
+ if (current_context->initial_array_prototype() == raw_array) { |
+ return true; |
} |
+ context = current_context->get(Context::NEXT_CONTEXT_LINK); |
} |
return false; |
} |