[turbofan] Port Crankshaft's weak objects mechanism to TurboFan.
Use the same mechanism that is already available for Crankshaft to not leak all kinds of things in TurboFan generated code. Long-term we will support weakness in a better way, but for now, just use the infrastructure that is already in place to avoid memory leaks via TurboFan generated code. R=jarin@chromium.org, ulan@chromium.org Review URL: https://codereview.chromium.org/1555743003 Cr-Commit-Position: refs/heads/master@{#33073}
This commit is contained in:
parent
cb21144baf
commit
84a88a1bd0
@ -544,6 +544,61 @@ OptimizedCompileJob::Status OptimizedCompileJob::OptimizeGraph() {
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object,
|
||||
Handle<Code> code) {
|
||||
Handle<WeakCell> cell = Code::WeakCellFor(code);
|
||||
Heap* heap = isolate->heap();
|
||||
Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object));
|
||||
dep = DependentCode::InsertWeakCode(dep, DependentCode::kWeakCodeGroup, cell);
|
||||
heap->AddWeakObjectToCodeDependency(object, dep);
|
||||
}
|
||||
|
||||
|
||||
void RegisterWeakObjectsInOptimizedCode(Handle<Code> code) {
|
||||
// TODO(turbofan): Move this to pipeline.cc once Crankshaft dies.
|
||||
Isolate* const isolate = code->GetIsolate();
|
||||
DCHECK(code->is_optimized_code());
|
||||
std::vector<Handle<Map>> maps;
|
||||
std::vector<Handle<HeapObject>> objects;
|
||||
{
|
||||
DisallowHeapAllocation no_gc;
|
||||
int const mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
|
||||
RelocInfo::ModeMask(RelocInfo::CELL);
|
||||
for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
|
||||
RelocInfo::Mode mode = it.rinfo()->rmode();
|
||||
if (mode == RelocInfo::CELL &&
|
||||
code->IsWeakObjectInOptimizedCode(it.rinfo()->target_cell())) {
|
||||
objects.push_back(handle(it.rinfo()->target_cell(), isolate));
|
||||
} else if (mode == RelocInfo::EMBEDDED_OBJECT &&
|
||||
code->IsWeakObjectInOptimizedCode(
|
||||
it.rinfo()->target_object())) {
|
||||
Handle<HeapObject> object(HeapObject::cast(it.rinfo()->target_object()),
|
||||
isolate);
|
||||
if (object->IsMap()) {
|
||||
maps.push_back(Handle<Map>::cast(object));
|
||||
} else {
|
||||
objects.push_back(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Handle<Map> map : maps) {
|
||||
if (map->dependent_code()->IsEmpty(DependentCode::kWeakCodeGroup)) {
|
||||
isolate->heap()->AddRetainedMap(map);
|
||||
}
|
||||
Map::AddDependentCode(map, DependentCode::kWeakCodeGroup, code);
|
||||
}
|
||||
for (Handle<HeapObject> object : objects) {
|
||||
AddWeakObjectToCodeDependency(isolate, object, code);
|
||||
}
|
||||
code->set_can_have_weak_objects(true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
|
||||
DCHECK(last_status() == SUCCEEDED);
|
||||
// TODO(turbofan): Currently everything is done in the first phase.
|
||||
@ -552,6 +607,7 @@ OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
|
||||
if (info()->is_deoptimization_enabled()) {
|
||||
info()->parse_info()->context()->native_context()->AddOptimizedCode(
|
||||
*info()->code());
|
||||
RegisterWeakObjectsInOptimizedCode(info()->code());
|
||||
}
|
||||
RecordOptimizationStats();
|
||||
return last_status();
|
||||
@ -576,6 +632,7 @@ OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
|
||||
}
|
||||
return SetLastStatus(BAILED_OUT);
|
||||
}
|
||||
RegisterWeakObjectsInOptimizedCode(optimized_code);
|
||||
info()->SetCode(optimized_code);
|
||||
}
|
||||
RecordOptimizationStats();
|
||||
|
@ -406,53 +406,6 @@ Representation LChunk::LookupLiteralRepresentation(
|
||||
}
|
||||
|
||||
|
||||
static void AddWeakObjectToCodeDependency(Isolate* isolate,
|
||||
Handle<HeapObject> object,
|
||||
Handle<Code> code) {
|
||||
Handle<WeakCell> cell = Code::WeakCellFor(code);
|
||||
Heap* heap = isolate->heap();
|
||||
Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object));
|
||||
dep = DependentCode::InsertWeakCode(dep, DependentCode::kWeakCodeGroup, cell);
|
||||
heap->AddWeakObjectToCodeDependency(object, dep);
|
||||
}
|
||||
|
||||
|
||||
void LChunk::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) const {
|
||||
DCHECK(code->is_optimized_code());
|
||||
ZoneList<Handle<Map> > maps(1, zone());
|
||||
ZoneList<Handle<HeapObject> > objects(1, zone());
|
||||
int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
|
||||
RelocInfo::ModeMask(RelocInfo::CELL);
|
||||
for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
|
||||
RelocInfo::Mode mode = it.rinfo()->rmode();
|
||||
if (mode == RelocInfo::CELL &&
|
||||
code->IsWeakObjectInOptimizedCode(it.rinfo()->target_cell())) {
|
||||
objects.Add(Handle<HeapObject>(it.rinfo()->target_cell()), zone());
|
||||
} else if (mode == RelocInfo::EMBEDDED_OBJECT &&
|
||||
code->IsWeakObjectInOptimizedCode(it.rinfo()->target_object())) {
|
||||
if (it.rinfo()->target_object()->IsMap()) {
|
||||
Handle<Map> map(Map::cast(it.rinfo()->target_object()));
|
||||
maps.Add(map, zone());
|
||||
} else {
|
||||
Handle<HeapObject> object(
|
||||
HeapObject::cast(it.rinfo()->target_object()));
|
||||
objects.Add(object, zone());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < maps.length(); i++) {
|
||||
if (maps.at(i)->dependent_code()->IsEmpty(DependentCode::kWeakCodeGroup)) {
|
||||
isolate()->heap()->AddRetainedMap(maps.at(i));
|
||||
}
|
||||
Map::AddDependentCode(maps.at(i), DependentCode::kWeakCodeGroup, code);
|
||||
}
|
||||
for (int i = 0; i < objects.length(); i++) {
|
||||
AddWeakObjectToCodeDependency(isolate(), objects.at(i), code);
|
||||
}
|
||||
code->set_can_have_weak_objects(true);
|
||||
}
|
||||
|
||||
|
||||
void LChunk::CommitDependencies(Handle<Code> code) const {
|
||||
if (!code->is_optimized_code()) return;
|
||||
HandleScope scope(isolate());
|
||||
@ -470,7 +423,6 @@ void LChunk::CommitDependencies(Handle<Code> code) const {
|
||||
}
|
||||
|
||||
info_->dependencies()->Commit(code);
|
||||
RegisterWeakObjectsInOptimizedCode(code);
|
||||
}
|
||||
|
||||
|
||||
|
@ -690,7 +690,6 @@ class LChunk : public ZoneObject {
|
||||
int spill_slot_count_;
|
||||
|
||||
private:
|
||||
void RegisterWeakObjectsInOptimizedCode(Handle<Code> code) const;
|
||||
void CommitDependencies(Handle<Code> code) const;
|
||||
|
||||
CompilationInfo* info_;
|
||||
|
@ -5238,8 +5238,6 @@ Object* Code::GetObjectFromEntryAddress(Address location_of_address) {
|
||||
|
||||
|
||||
bool Code::CanContainWeakObjects() {
|
||||
// is_turbofanned() implies !can_have_weak_objects().
|
||||
DCHECK(!is_optimized_code() || !is_turbofanned() || !can_have_weak_objects());
|
||||
return is_optimized_code() && can_have_weak_objects();
|
||||
}
|
||||
|
||||
|
@ -121,10 +121,13 @@
|
||||
# optimized and hence scripts don't "return" the correct value. Fix this.
|
||||
'test-compiler/CompileFunctionInContext*': [PASS, NO_VARIANTS],
|
||||
|
||||
# TurboFan doesn't support allocation sites currently.
|
||||
'test-heap/CellsInOptimizedCodeAreWeak': [PASS, NO_VARIANTS],
|
||||
'test-heap/EnsureAllocationSiteDependentCodesProcessed': [PASS, NO_VARIANTS],
|
||||
# TODO(bmeurer): TurboFan embeds strong references to all kinds of objects
|
||||
# via deoptimization data (Crankshaft also does this, but lack proper test
|
||||
# coverage).
|
||||
'test-heap/ObjectsInOptimizedCodeAreWeak': [PASS, NO_VARIANTS],
|
||||
|
||||
# TurboFan doesn't support allocation sites currently.
|
||||
'test-heap/EnsureAllocationSiteDependentCodesProcessed': [PASS, NO_VARIANTS],
|
||||
'test-heap/OptimizedPretenuringAllocationFolding': [PASS, NO_VARIANTS],
|
||||
'test-heap/OptimizedPretenuringdoubleArrayLiterals': [PASS, NO_VARIANTS],
|
||||
'test-heap/OptimizedPretenuringDoubleArrayProperties': [PASS, NO_VARIANTS],
|
||||
|
@ -4766,17 +4766,19 @@ TEST(CellsInOptimizedCodeAreWeak) {
|
||||
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;})();");
|
||||
CompileRun(
|
||||
"bar = (function() {"
|
||||
" function bar() {"
|
||||
" return foo(1);"
|
||||
" };"
|
||||
" var foo = function(x) { with (x) { return 1 + x; } };"
|
||||
" %NeverOptimizeFunction(foo);"
|
||||
" bar(foo);"
|
||||
" bar(foo);"
|
||||
" bar(foo);"
|
||||
" %OptimizeFunctionOnNextCall(bar);"
|
||||
" bar(foo);"
|
||||
" return bar;})();");
|
||||
|
||||
Handle<JSFunction> bar = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
|
||||
*v8::Local<v8::Function>::Cast(CcTest::global()
|
||||
@ -4809,15 +4811,17 @@ TEST(ObjectsInOptimizedCodeAreWeak) {
|
||||
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();");
|
||||
CompileRun(
|
||||
"function bar() {"
|
||||
" return foo(1);"
|
||||
"};"
|
||||
"function foo(x) { with (x) { return 1 + x; } };"
|
||||
"%NeverOptimizeFunction(foo);"
|
||||
"bar();"
|
||||
"bar();"
|
||||
"bar();"
|
||||
"%OptimizeFunctionOnNextCall(bar);"
|
||||
"bar();");
|
||||
|
||||
Handle<JSFunction> bar = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
|
||||
*v8::Local<v8::Function>::Cast(CcTest::global()
|
||||
|
Loading…
Reference in New Issue
Block a user