Commit 2638dca4 authored by ulan@chromium.org's avatar ulan@chromium.org

Make cells pointing to JSObjects weak in optimized code.

This is done similar to weak embedded objects in optimized code (r17102). The
reference from optimized code to a cell is treated weakly in marking visitors
if the cell points to a JSObject. After marking we iterate over all cells
embedded in optimized code. If a cell is not marked but its value is marked,
then we revive the cell by marking it. Otherwise, the cell value is dead, so
we mark the code for deoptimization.

BUG=v8:2073
TEST=cctest/test-heap/CellsInOptimizedCodeAreWeak
LOG=Y
R=hpayer@chromium.org, mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/117483002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18616 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4e657857
......@@ -5398,7 +5398,7 @@ class Internals {
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
static const int kEmptyStringRootIndex = 135;
static const int kEmptyStringRootIndex = 136;
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
......
......@@ -3399,6 +3399,11 @@ bool Heap::CreateInitialObjects() {
}
set_natives_source_cache(FixedArray::cast(obj));
{ MaybeObject* maybe_obj = AllocateCell(undefined_value());
if (!maybe_obj->ToObject(&obj)) return false;
}
set_undefined_cell(Cell::cast(obj));
// Allocate object to hold object observation state.
{ MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
if (!maybe_obj->ToObject(&obj)) return false;
......
......@@ -185,6 +185,7 @@ namespace internal {
V(Smi, construct_stub_deopt_pc_offset, ConstructStubDeoptPCOffset) \
V(Smi, getter_stub_deopt_pc_offset, GetterStubDeoptPCOffset) \
V(Smi, setter_stub_deopt_pc_offset, SetterStubDeoptPCOffset) \
V(Cell, undefined_cell, UndefineCell) \
V(JSObject, observation_state, ObservationState) \
V(Map, external_map, ExternalMap) \
V(Symbol, frozen_symbol, FrozenSymbol) \
......
......@@ -150,15 +150,26 @@ int LCodeGenBase::GetNextEmittedBlock() const {
void LCodeGenBase::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) {
ZoneList<Handle<Map> > maps(1, zone());
ZoneList<Handle<JSObject> > objects(1, zone());
int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
ZoneList<Handle<Cell> > cells(1, zone());
int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::CELL);
for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
if (Code::IsWeakEmbeddedObject(code->kind(), it.rinfo()->target_object())) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::CELL &&
Code::IsWeakEmbeddedObject(code->kind(), it.rinfo()->target_cell())) {
Handle<Cell> cell(it.rinfo()->target_cell());
cells.Add(cell, zone());
} else if (mode == RelocInfo::EMBEDDED_OBJECT &&
Code::IsWeakEmbeddedObject(code->kind(), it.rinfo()->target_object())) {
if (it.rinfo()->target_object()->IsMap()) {
Handle<Map> map(Map::cast(it.rinfo()->target_object()));
maps.Add(map, zone());
} else if (it.rinfo()->target_object()->IsJSObject()) {
Handle<JSObject> object(JSObject::cast(it.rinfo()->target_object()));
objects.Add(object, zone());
} else if (it.rinfo()->target_object()->IsCell()) {
Handle<Cell> cell(Cell::cast(it.rinfo()->target_object()));
cells.Add(cell, zone());
}
}
}
......@@ -174,6 +185,9 @@ void LCodeGenBase::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) {
for (int i = 0; i < objects.length(); i++) {
AddWeakObjectToCodeDependency(isolate()->heap(), objects.at(i), code);
}
for (int i = 0; i < cells.length(); i++) {
AddWeakObjectToCodeDependency(isolate()->heap(), cells.at(i), code);
}
}
......
......@@ -98,6 +98,14 @@ class VerifyMarkingVisitor: public ObjectVisitor {
}
}
void VisitCell(RelocInfo* rinfo) {
Code* code = rinfo->host();
ASSERT(rinfo->rmode() == RelocInfo::CELL);
if (!Code::IsWeakEmbeddedObject(code->kind(), rinfo->target_cell())) {
ObjectVisitor::VisitCell(rinfo);
}
}
private:
Heap* heap_;
};
......@@ -2551,6 +2559,16 @@ void MarkCompactCollector::ClearNonLiveReferences() {
if (!table->IsKey(key)) continue;
uint32_t value_index = table->EntryToValueIndex(i);
Object* value = table->get(value_index);
if (key->IsCell() && !IsMarked(key)) {
Cell* cell = Cell::cast(key);
Object* object = cell->value();
if (IsMarked(object)) {
MarkBit mark = Marking::MarkBitFrom(cell);
SetMark(cell, mark);
Object** value_slot = HeapObject::RawField(cell, Cell::kValueOffset);
RecordSlot(value_slot, value_slot, *value_slot);
}
}
if (IsMarked(key)) {
if (!IsMarked(value)) {
HeapObject* obj = HeapObject::cast(value);
......
......@@ -261,6 +261,9 @@ void StaticMarkingVisitor<StaticVisitor>::VisitEmbeddedPointer(
ASSERT(!rinfo->target_object()->IsConsString());
HeapObject* object = HeapObject::cast(rinfo->target_object());
heap->mark_compact_collector()->RecordRelocSlot(rinfo, object);
// TODO(ulan): It could be better to record slots only for strongly embedded
// objects here and record slots for weakly embedded object during clearing
// of non-live references in mark-compact.
if (!Code::IsWeakEmbeddedObject(rinfo->host()->kind(), object)) {
StaticVisitor::MarkObject(heap, object);
}
......@@ -272,7 +275,10 @@ void StaticMarkingVisitor<StaticVisitor>::VisitCell(
Heap* heap, RelocInfo* rinfo) {
ASSERT(rinfo->rmode() == RelocInfo::CELL);
Cell* cell = rinfo->target_cell();
StaticVisitor::MarkObject(heap, cell);
// No need to record slots because the cell space is not compacted during GC.
if (!Code::IsWeakEmbeddedObject(rinfo->host()->kind(), cell)) {
StaticVisitor::MarkObject(heap, cell);
}
}
......
......@@ -10311,11 +10311,15 @@ void Code::InvalidateRelocation() {
void Code::InvalidateEmbeddedObjects() {
Object* undefined = GetHeap()->undefined_value();
int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
Cell* undefined_cell = GetHeap()->undefined_cell();
int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::CELL);
for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
} else if (mode == RelocInfo::CELL) {
it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
}
}
}
......@@ -11277,7 +11281,8 @@ bool Code::IsWeakEmbeddedObject(Kind kind, Object* object) {
FLAG_weak_embedded_maps_in_optimized_code;
}
if (object->IsJSObject()) {
if (object->IsJSObject() ||
(object->IsCell() && Cell::cast(object)->value()->IsJSObject())) {
return FLAG_weak_embedded_objects_in_optimized_code;
}
......
......@@ -3664,3 +3664,87 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) {
int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
CHECK(!(site->dependent_code()->is_code_at(index)));
}
TEST(CellsInOptimizedCodeAreWeak) {
if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
i::FLAG_weak_embedded_objects_in_optimized_code = true;
i::FLAG_allow_natives_syntax = true;
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
v8::internal::Heap* heap = CcTest::heap();
if (!isolate->use_crankshaft()) return;
HandleScope outer_scope(heap->isolate());
Handle<Code> code;
{
LocalContext context;
HandleScope scope(heap->isolate());
CompileRun("bar = (function() {"
" function bar() {"
" return foo(1);"
" };"
" var foo = function(x) { with (x) { return 1 + x; } };"
" bar(foo);"
" bar(foo);"
" bar(foo);"
" %OptimizeFunctionOnNextCall(bar);"
" bar(foo);"
" return bar;})();");
Handle<JSFunction> bar =
v8::Utils::OpenHandle(
*v8::Handle<v8::Function>::Cast(
CcTest::global()->Get(v8_str("bar"))));
code = scope.CloseAndEscape(Handle<Code>(bar->code()));
}
// Now make sure that a gc should get rid of the function
for (int i = 0; i < 4; i++) {
heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
}
ASSERT(code->marked_for_deoptimization());
}
TEST(ObjectsInOptimizedCodeAreWeak) {
if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
i::FLAG_weak_embedded_objects_in_optimized_code = true;
i::FLAG_allow_natives_syntax = true;
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
v8::internal::Heap* heap = CcTest::heap();
if (!isolate->use_crankshaft()) return;
HandleScope outer_scope(heap->isolate());
Handle<Code> code;
{
LocalContext context;
HandleScope scope(heap->isolate());
CompileRun("function bar() {"
" return foo(1);"
"};"
"function foo(x) { with (x) { return 1 + x; } };"
"bar();"
"bar();"
"bar();"
"%OptimizeFunctionOnNextCall(bar);"
"bar();");
Handle<JSFunction> bar =
v8::Utils::OpenHandle(
*v8::Handle<v8::Function>::Cast(
CcTest::global()->Get(v8_str("bar"))));
code = scope.CloseAndEscape(Handle<Code>(bar->code()));
}
// Now make sure that a gc should get rid of the function
for (int i = 0; i < 4; i++) {
heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
}
ASSERT(code->marked_for_deoptimization());
}
......@@ -226,32 +226,32 @@ KNOWN_OBJECTS = {
("OLD_POINTER_SPACE", 0x09521): "TerminationException",
("OLD_POINTER_SPACE", 0x09531): "MessageListeners",
("OLD_POINTER_SPACE", 0x0954d): "CodeStubs",
("OLD_POINTER_SPACE", 0x0a9d9): "NonMonomorphicCache",
("OLD_POINTER_SPACE", 0x0afed): "PolymorphicCodeCache",
("OLD_POINTER_SPACE", 0x0aff5): "NativesSourceCache",
("OLD_POINTER_SPACE", 0x0b03d): "EmptyScript",
("OLD_POINTER_SPACE", 0x0b075): "IntrinsicFunctionNames",
("OLD_POINTER_SPACE", 0x0e091): "ObservationState",
("OLD_POINTER_SPACE", 0x0e09d): "FrozenSymbol",
("OLD_POINTER_SPACE", 0x0e0a9): "ElementsTransitionSymbol",
("OLD_POINTER_SPACE", 0x0e0b5): "EmptySlowElementDictionary",
("OLD_POINTER_SPACE", 0x0e251): "ObservedSymbol",
("OLD_POINTER_SPACE", 0x29861): "StringTable",
("OLD_POINTER_SPACE", 0x10485): "NonMonomorphicCache",
("OLD_POINTER_SPACE", 0x10a99): "PolymorphicCodeCache",
("OLD_POINTER_SPACE", 0x10aa1): "NativesSourceCache",
("OLD_POINTER_SPACE", 0x10aed): "EmptyScript",
("OLD_POINTER_SPACE", 0x10b25): "IntrinsicFunctionNames",
("OLD_POINTER_SPACE", 0x13b41): "ObservationState",
("OLD_POINTER_SPACE", 0x13b4d): "FrozenSymbol",
("OLD_POINTER_SPACE", 0x13b5d): "ElementsTransitionSymbol",
("OLD_POINTER_SPACE", 0x13b6d): "EmptySlowElementDictionary",
("OLD_POINTER_SPACE", 0x13d09): "ObservedSymbol",
("OLD_POINTER_SPACE", 0x32325): "StringTable",
("OLD_DATA_SPACE", 0x08099): "EmptyDescriptorArray",
("OLD_DATA_SPACE", 0x080a1): "EmptyFixedArray",
("OLD_DATA_SPACE", 0x080a9): "NanValue",
("OLD_DATA_SPACE", 0x08141): "EmptyByteArray",
("OLD_DATA_SPACE", 0x08269): "EmptyExternalByteArray",
("OLD_DATA_SPACE", 0x08275): "EmptyExternalUnsignedByteArray",
("OLD_DATA_SPACE", 0x08281): "EmptyExternalShortArray",
("OLD_DATA_SPACE", 0x0828d): "EmptyExternalUnsignedShortArray",
("OLD_DATA_SPACE", 0x08299): "EmptyExternalIntArray",
("OLD_DATA_SPACE", 0x082a5): "EmptyExternalUnsignedIntArray",
("OLD_DATA_SPACE", 0x082b1): "EmptyExternalFloatArray",
("OLD_DATA_SPACE", 0x082bd): "EmptyExternalDoubleArray",
("OLD_DATA_SPACE", 0x082c9): "EmptyExternalPixelArray",
("OLD_DATA_SPACE", 0x082d5): "InfinityValue",
("OLD_DATA_SPACE", 0x082e1): "MinusZeroValue",
("CODE_SPACE", 0x111a1): "JsConstructEntryCode",
("CODE_SPACE", 0x18bc1): "JsEntryCode",
("OLD_DATA_SPACE", 0x08279): "EmptyExternalByteArray",
("OLD_DATA_SPACE", 0x08285): "EmptyExternalUnsignedByteArray",
("OLD_DATA_SPACE", 0x08291): "EmptyExternalShortArray",
("OLD_DATA_SPACE", 0x0829d): "EmptyExternalUnsignedShortArray",
("OLD_DATA_SPACE", 0x082a9): "EmptyExternalIntArray",
("OLD_DATA_SPACE", 0x082b5): "EmptyExternalUnsignedIntArray",
("OLD_DATA_SPACE", 0x082c1): "EmptyExternalFloatArray",
("OLD_DATA_SPACE", 0x082cd): "EmptyExternalDoubleArray",
("OLD_DATA_SPACE", 0x082d9): "EmptyExternalPixelArray",
("OLD_DATA_SPACE", 0x082e5): "InfinityValue",
("OLD_DATA_SPACE", 0x082f1): "MinusZeroValue",
("CODE_SPACE", 0x14181): "JsConstructEntryCode",
("CODE_SPACE", 0x15c61): "JsEntryCode",
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment