Serializer: clear next link in weak cells.
If we do not clear next links during serialization, the serializer would simply follow those links and serialize arbitrary objects held by weak cells. This breaks the invariant in the code serializer, which crashes if it sees context-dependent objects. R=ulan@chromium.org BUG=chromium:503552 LOG=Y Review URL: https://codereview.chromium.org/1203973002 Cr-Commit-Position: refs/heads/master@{#29255}
This commit is contained in:
parent
8636e105d1
commit
f1982eb490
@ -3126,7 +3126,7 @@ AllocationResult Heap::AllocateWeakCell(HeapObject* value) {
|
||||
}
|
||||
result->set_map_no_write_barrier(weak_cell_map());
|
||||
WeakCell::cast(result)->initialize(value);
|
||||
WeakCell::cast(result)->set_next(the_hole_value(), SKIP_WRITE_BARRIER);
|
||||
WeakCell::cast(result)->clear_next(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2647,7 +2647,6 @@ void MarkCompactCollector::AbortWeakCollections() {
|
||||
|
||||
|
||||
void MarkCompactCollector::ProcessAndClearWeakCells() {
|
||||
HeapObject* the_hole = heap()->the_hole_value();
|
||||
Object* weak_cell_obj = heap()->encountered_weak_cells();
|
||||
while (weak_cell_obj != Smi::FromInt(0)) {
|
||||
WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
|
||||
@ -2682,19 +2681,18 @@ void MarkCompactCollector::ProcessAndClearWeakCells() {
|
||||
RecordSlot(slot, slot, *slot);
|
||||
}
|
||||
weak_cell_obj = weak_cell->next();
|
||||
weak_cell->set_next(the_hole, SKIP_WRITE_BARRIER);
|
||||
weak_cell->clear_next(heap());
|
||||
}
|
||||
heap()->set_encountered_weak_cells(Smi::FromInt(0));
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::AbortWeakCells() {
|
||||
Object* the_hole = heap()->the_hole_value();
|
||||
Object* weak_cell_obj = heap()->encountered_weak_cells();
|
||||
while (weak_cell_obj != Smi::FromInt(0)) {
|
||||
WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
|
||||
weak_cell_obj = weak_cell->next();
|
||||
weak_cell->set_next(the_hole, SKIP_WRITE_BARRIER);
|
||||
weak_cell->clear_next(heap());
|
||||
}
|
||||
heap()->set_encountered_weak_cells(Smi::FromInt(0));
|
||||
}
|
||||
|
@ -329,11 +329,10 @@ void StaticMarkingVisitor<StaticVisitor>::VisitWeakCell(Map* map,
|
||||
HeapObject* object) {
|
||||
Heap* heap = map->GetHeap();
|
||||
WeakCell* weak_cell = reinterpret_cast<WeakCell*>(object);
|
||||
Object* the_hole = heap->the_hole_value();
|
||||
// Enqueue weak cell in linked list of encountered weak collections.
|
||||
// We can ignore weak cells with cleared values because they will always
|
||||
// contain smi zero.
|
||||
if (weak_cell->next() == the_hole && !weak_cell->cleared()) {
|
||||
if (weak_cell->next_cleared() && !weak_cell->cleared()) {
|
||||
weak_cell->set_next(heap->encountered_weak_cells(),
|
||||
UPDATE_WEAK_WRITE_BARRIER);
|
||||
heap->set_encountered_weak_cells(weak_cell);
|
||||
|
@ -1925,6 +1925,14 @@ void WeakCell::set_next(Object* val, WriteBarrierMode mode) {
|
||||
}
|
||||
|
||||
|
||||
void WeakCell::clear_next(Heap* heap) {
|
||||
set_next(heap->the_hole_value(), SKIP_WRITE_BARRIER);
|
||||
}
|
||||
|
||||
|
||||
bool WeakCell::next_cleared() { return next()->IsTheHole(); }
|
||||
|
||||
|
||||
int JSObject::GetHeaderSize() {
|
||||
InstanceType type = map()->instance_type();
|
||||
// Check for the most common kind of JavaScript object before
|
||||
|
@ -9610,6 +9610,10 @@ class WeakCell : public HeapObject {
|
||||
|
||||
DECL_ACCESSORS(next, Object)
|
||||
|
||||
inline void clear_next(Heap* heap);
|
||||
|
||||
inline bool next_cleared();
|
||||
|
||||
DECLARE_CAST(WeakCell)
|
||||
|
||||
DECLARE_PRINTER(WeakCell)
|
||||
|
@ -1851,6 +1851,28 @@ void Serializer::ObjectSerializer::SerializeExternalString() {
|
||||
}
|
||||
|
||||
|
||||
// Clear and later restore the next link in the weak cell, if the object is one.
|
||||
class UnlinkWeakCellScope {
|
||||
public:
|
||||
explicit UnlinkWeakCellScope(HeapObject* object) : weak_cell_(NULL) {
|
||||
if (object->IsWeakCell()) {
|
||||
weak_cell_ = WeakCell::cast(object);
|
||||
next_ = weak_cell_->next();
|
||||
weak_cell_->clear_next(object->GetHeap());
|
||||
}
|
||||
}
|
||||
|
||||
~UnlinkWeakCellScope() {
|
||||
if (weak_cell_) weak_cell_->set_next(next_, UPDATE_WEAK_WRITE_BARRIER);
|
||||
}
|
||||
|
||||
private:
|
||||
WeakCell* weak_cell_;
|
||||
Object* next_;
|
||||
DisallowHeapAllocation no_gc_;
|
||||
};
|
||||
|
||||
|
||||
void Serializer::ObjectSerializer::Serialize() {
|
||||
if (FLAG_trace_serializer) {
|
||||
PrintF(" Encoding heap object: ");
|
||||
@ -1910,6 +1932,8 @@ void Serializer::ObjectSerializer::Serialize() {
|
||||
return;
|
||||
}
|
||||
|
||||
UnlinkWeakCellScope unlink_weak_cell(object_);
|
||||
|
||||
object_->IterateBody(map->instance_type(), size, this);
|
||||
OutputRawData(object_->address() + size);
|
||||
}
|
||||
@ -1934,6 +1958,8 @@ void Serializer::ObjectSerializer::SerializeDeferred() {
|
||||
serializer_->PutBackReference(object_, reference);
|
||||
sink_->PutInt(size >> kPointerSizeLog2, "deferred object size");
|
||||
|
||||
UnlinkWeakCellScope unlink_weak_cell(object_);
|
||||
|
||||
object_->IterateBody(map->instance_type(), size, this);
|
||||
OutputRawData(object_->address() + size);
|
||||
}
|
||||
|
@ -1658,6 +1658,31 @@ TEST(SerializeInternalReference) {
|
||||
}
|
||||
|
||||
|
||||
TEST(Regress503552) {
|
||||
// Test that the code serializer can deal with weak cells that form a linked
|
||||
// list during incremental marking.
|
||||
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
HandleScope scope(isolate);
|
||||
Handle<String> source = isolate->factory()->NewStringFromAsciiChecked(
|
||||
"function f() {} function g() {}");
|
||||
ScriptData* script_data = NULL;
|
||||
Handle<SharedFunctionInfo> shared = Compiler::CompileScript(
|
||||
source, Handle<String>(), 0, 0, v8::ScriptOriginOptions(),
|
||||
Handle<Object>(), Handle<Context>(isolate->native_context()), NULL,
|
||||
&script_data, v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE,
|
||||
false);
|
||||
delete script_data;
|
||||
|
||||
SimulateIncrementalMarking(isolate->heap());
|
||||
|
||||
script_data = CodeSerializer::Serialize(isolate, shared, source);
|
||||
delete script_data;
|
||||
}
|
||||
|
||||
|
||||
TEST(SerializationMemoryStats) {
|
||||
FLAG_profile_deserialization = true;
|
||||
FLAG_always_opt = false;
|
||||
|
Loading…
Reference in New Issue
Block a user