Chromium Code Reviews| Index: src/isolate.cc |
| diff --git a/src/isolate.cc b/src/isolate.cc |
| index aeaf82ed829f5525edc4384f3bd361d307177876..6d37d1d7d7634e9b24f37fdea2f85b3d26d4b750 100644 |
| --- a/src/isolate.cc |
| +++ b/src/isolate.cc |
| @@ -2433,20 +2433,83 @@ bool Isolate::use_crankshaft() const { |
| } |
| +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) { |
| + // |
| + return is_concat_spreadable_set; |
| + } |
| + |
| + Handle<Object> array_prototype(array_function()->prototype(), this); |
| + Handle<Symbol> key(factory()->is_concat_spreadable_symbol()); |
| + Handle<Object> value; |
| + MaybeHandle<Object> maybeValue = |
| + i::Runtime::GetObjectProperty(this, array_prototype, key); |
| + if (maybeValue.ToHandle(&value) && !value->IsUndefined()) { |
|
Toon Verwaest
2015/11/02 12:32:45
Plus o[@@isConcatSpreadable] = undefined
Camillo Bruni
2015/11/03 14:49:25
?
|
| + // 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()); |
|
Toon Verwaest
2015/11/02 12:32:45
key = factory()->is_concat_spreadable_symbol();
Camillo Bruni
2015/11/03 14:49:25
right
|
| + 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(kArrayElementsProtectorInvalid), this)); |
| +} |
| + |
| + |
| bool Isolate::IsFastArrayConstructorPrototypeChainIntact() { |
| - PropertyCell* no_elements_cell = heap()->array_protector(); |
| - bool cell_reports_intact = |
| - no_elements_cell->value()->IsSmi() && |
| - Smi::cast(no_elements_cell->value())->value() == kArrayProtectorValid; |
| + PropertyCell* no_elements_cell = heap()->array_elements_protector(); |
| + bool cell_reports_intact = no_elements_cell->value()->IsSmi() && |
| + Smi::cast(no_elements_cell->value())->value() == |
| + kArrayElementsProtectorValid; |
| #ifdef DEBUG |
| Map* root_array_map = |
| get_initial_js_array_map(GetInitialFastElementsKind()); |
| Context* native_context = context()->native_context(); |
| - JSObject* initial_array_proto = JSObject::cast( |
| - native_context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX)); |
| - JSObject* initial_object_proto = JSObject::cast( |
| - native_context->get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX)); |
| + JSObject* initial_array_proto = |
| + JSObject::cast(native_context->initial_array_prototype()); |
| + JSObject* initial_object_proto = |
| + JSObject::cast(native_context->initial_object_prototype()); |
| if (root_array_map == NULL || initial_array_proto == initial_object_proto) { |
| // We are in the bootstrapping process, and the entire check sequence |
| @@ -2457,34 +2520,34 @@ bool Isolate::IsFastArrayConstructorPrototypeChainIntact() { |
| // Check that the array prototype hasn't been altered WRT empty elements. |
| if (root_array_map->prototype() != initial_array_proto) { |
| DCHECK_EQ(false, cell_reports_intact); |
| - return cell_reports_intact; |
| + return false; |
| } |
| FixedArrayBase* elements = initial_array_proto->elements(); |
| if (elements != heap()->empty_fixed_array() && |
| elements != heap()->empty_slow_element_dictionary()) { |
| DCHECK_EQ(false, cell_reports_intact); |
| - return cell_reports_intact; |
| + return false; |
| } |
| // Check that the object prototype hasn't been altered WRT empty elements. |
| PrototypeIterator iter(this, initial_array_proto); |
| if (iter.IsAtEnd() || iter.GetCurrent() != initial_object_proto) { |
| DCHECK_EQ(false, cell_reports_intact); |
| - return cell_reports_intact; |
| + return false; |
| } |
| elements = initial_object_proto->elements(); |
| if (elements != heap()->empty_fixed_array() && |
| elements != heap()->empty_slow_element_dictionary()) { |
| DCHECK_EQ(false, cell_reports_intact); |
| - return cell_reports_intact; |
| + return false; |
| } |
| iter.Advance(); |
| if (!iter.IsAtEnd()) { |
| DCHECK_EQ(false, cell_reports_intact); |
| - return cell_reports_intact; |
| + return false; |
| } |
| #endif |
| @@ -2494,37 +2557,25 @@ bool Isolate::IsFastArrayConstructorPrototypeChainIntact() { |
| void Isolate::UpdateArrayProtectorOnSetElement(Handle<JSObject> object) { |
| - 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) { |
| - 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_elements_protector(), |
| + handle(Smi::FromInt(kArrayElementsProtectorInvalid), 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); |
| + if (!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() == *array) { |
| + return true; |
| } |
| + context = current_context->get(Context::NEXT_CONTEXT_LINK); |
| } |
| return false; |
| } |