[heap] Fix a map creation data race with concurrent marking.

The race happens when an object transitions to a newly created map.
The map initializing stores can be reordered after object->set_map(map),
which will cause the concurrent marker to observe inconsistent map.

The fix is to use store-release when setting the map pointer and
acquire-load when reading the map in the concurrent marker.

BUG=chromium:694255

Change-Id: I4fd6bc27dd70ff1a30f56a4cec13310ccdd627c8
Reviewed-on: https://chromium-review.googlesource.com/528118
Reviewed-by: Hannes Payer <hpayer@chromium.org>
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45876}
This commit is contained in:
Ulan Degenbaev 2017-06-09 12:06:11 +02:00 committed by Commit Bot
parent 0aa78b9e5b
commit d906f81502
7 changed files with 14 additions and 7 deletions

View File

@ -498,9 +498,9 @@ class ArrayConcatVisitor {
isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
Handle<Map> map = JSObject::GetElementsTransitionMap(
array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
array->set_map(*map);
array->set_length(*length);
array->set_elements(*storage_fixed_array());
array->synchronized_set_map(*map);
return array;
}

View File

@ -1864,8 +1864,8 @@ Handle<JSGlobalObject> Factory::NewJSGlobalObject(
new_map->set_dictionary_map(true);
// Set up the global object as a normalized object.
global->set_map(*new_map);
global->set_properties(*dictionary);
global->synchronized_set_map(*new_map);
// Make sure result is a global object with properties in dictionary.
DCHECK(global->IsJSGlobalObject() && !global->HasFastProperties());

View File

@ -266,7 +266,8 @@ void ConcurrentMarking::Run() {
if (new_space_top <= addr && addr < new_space_limit) {
deque_->Push(object, MarkingThread::kConcurrent, TargetDeque::kBailout);
} else {
bytes_marked += visitor_->Visit(object);
Map* map = object->synchronized_map();
bytes_marked += visitor_->Visit(map, object);
}
}
}

View File

@ -487,7 +487,12 @@ inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) {
template <typename ResultType, typename ConcreteVisitor>
ResultType HeapVisitor<ResultType, ConcreteVisitor>::Visit(HeapObject* object) {
Map* map = object->map();
return Visit(object->map(), object);
}
template <typename ResultType, typename ConcreteVisitor>
ResultType HeapVisitor<ResultType, ConcreteVisitor>::Visit(Map* map,
HeapObject* object) {
ConcreteVisitor* visitor = static_cast<ConcreteVisitor*>(this);
switch (static_cast<VisitorId>(map->visitor_id())) {
#define CASE(type) \

View File

@ -387,6 +387,7 @@ template <typename ResultType, typename ConcreteVisitor>
class HeapVisitor : public ObjectVisitor {
public:
ResultType Visit(HeapObject* object);
ResultType Visit(Map* map, HeapObject* object);
protected:
// A guard predicate for visiting the object.

View File

@ -3822,7 +3822,7 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map,
CHECK(new_map->is_dictionary_map());
// Slow-to-slow migration is trivial.
object->set_map(*new_map);
object->synchronized_set_map(*new_map);
} else if (!new_map->is_dictionary_map()) {
MigrateFastToFast(object, new_map);
if (old_map->is_prototype_map()) {
@ -15298,7 +15298,7 @@ void JSObject::SetImmutableProto(Handle<JSObject> object) {
if (map->is_immutable_proto()) return;
Handle<Map> new_map = Map::TransitionToImmutableProto(map);
object->set_map(*new_map);
object->synchronized_set_map(*new_map);
}
void JSObject::EnsureCanContainElements(Handle<JSObject> object,

View File

@ -111,7 +111,7 @@ static Handle<Object> CreateArrayLiteralBoilerplate(
Context* native_context = isolate->context()->native_context();
Object* map =
native_context->get(Context::ArrayMapIndex(constant_elements_kind));
object->set_map(Map::cast(map));
object->synchronized_set_map(Map::cast(map));
}
Handle<FixedArrayBase> copied_elements_values;