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; |
} |