Revision: 19635
Author: [email protected]
Date: Mon Mar 3 11:11:39 2014 UTC
Log: Clear optimized code cache in shared function info when code gets
deoptimized.
This adds a pointer to the shared function info into deoptimization data of
an optimized code. Whenever the code is deoptimized, it clears the cache in
the shared function info.
This fixes the problem when the optimized function dies in new space GC
before the code is deoptimized due to code dependency and before the
optimized code cache is cleared in old space GC (see
mjsunit/regress/regress-343609.js).
This partially reverts r19603 because we need to be able to evict specific
code from the optimized code cache.
BUG=343609
LOG=Y
TEST=mjsunit/regress/regress-343609.js
[email protected]
Review URL: https://codereview.chromium.org/184923002
http://code.google.com/p/v8/source/detail?r=19635
Added:
/branches/bleeding_edge/test/mjsunit/regress/regress-343609.js
Modified:
/branches/bleeding_edge/src/a64/deoptimizer-a64.cc
/branches/bleeding_edge/src/a64/lithium-codegen-a64.cc
/branches/bleeding_edge/src/arm/deoptimizer-arm.cc
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/compiler.cc
/branches/bleeding_edge/src/deoptimizer.cc
/branches/bleeding_edge/src/factory.cc
/branches/bleeding_edge/src/ia32/deoptimizer-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/mips/deoptimizer-mips.cc
/branches/bleeding_edge/src/mips/lithium-codegen-mips.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/x64/deoptimizer-x64.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/test/cctest/test-heap.cc
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-343609.js Mon Mar
3 11:11:39 2014 UTC
@@ -0,0 +1,66 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --block-concurrent-recompilation
+// Flags: --no-concurrent-osr --expose-gc
+
+function Ctor() {
+ this.a = 1;
+}
+
+function get_closure() {
+ return function add_field(obj) {
+ obj.c = 3;
+ obj.a = obj.a + obj.c;
+ return obj.a;
+ }
+}
+function get_closure2() {
+ return function cc(obj) {
+ obj.c = 3;
+ obj.a = obj.a + obj.c;
+ }
+}
+
+function dummy() {
+ (function () {
+ var o = {c: 10};
+ var f1 = get_closure2();
+ f1(o);
+ f1(o);
+ %OptimizeFunctionOnNextCall(f1);
+ f1(o);
+ })();
+}
+
+var o = new Ctor();
+function opt() {
+ (function () {
+ var f1 = get_closure();
+ f1(new Ctor());
+ f1(new Ctor());
+ %OptimizeFunctionOnNextCall(f1);
+ f1(o);
+ })();
+}
+
+// Optimize add_field and install its code in optimized code cache.
+opt();
+opt();
+opt();
+
+// Optimize dummy function to remove the add_field from head of optimized
+// function list in the context.
+dummy();
+dummy();
+
+// Kill add_field in new space GC.
+for(var i = 0; i < 3; i++) gc(true);
+
+// Trigger deopt.
+o.c = 2.2;
+
+// Fetch optimized code of add_field from cache and crash.
+var f2 = get_closure();
+f2(new Ctor());
=======================================
--- /branches/bleeding_edge/src/a64/deoptimizer-a64.cc Fri Feb 28 12:41:25
2014 UTC
+++ /branches/bleeding_edge/src/a64/deoptimizer-a64.cc Mon Mar 3 11:11:39
2014 UTC
@@ -53,15 +53,17 @@
// TODO(jkummerow): if (FLAG_zap_code_space), make the code object's
// entry sequence unusable (see other architectures).
- // For each LLazyBailout instruction insert a call to the corresponding
- // deoptimization entry.
DeoptimizationInputData* deopt_data =
DeoptimizationInputData::cast(code->deoptimization_data());
+ SharedFunctionInfo* shared =
+ SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
+ shared->EvictFromOptimizedCodeMap(code, "deoptimized code");
Address code_start_address = code->instruction_start();
#ifdef DEBUG
Address prev_call_address = NULL;
#endif
-
+ // For each LLazyBailout instruction insert a call to the corresponding
+ // deoptimization entry.
for (int i = 0; i < deopt_data->DeoptCount(); i++) {
if (deopt_data->Pc(i)->value() == -1) continue;
=======================================
--- /branches/bleeding_edge/src/a64/lithium-codegen-a64.cc Thu Feb 27
17:33:25 2014 UTC
+++ /branches/bleeding_edge/src/a64/lithium-codegen-a64.cc Mon Mar 3
11:11:39 2014 UTC
@@ -919,6 +919,11 @@
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
+ if (info_->IsOptimizing()) {
+ data->SetSharedFunctionInfo(*info_->shared_info());
+ } else {
+ data->SetSharedFunctionInfo(Smi::FromInt(0));
+ }
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
=======================================
--- /branches/bleeding_edge/src/arm/deoptimizer-arm.cc Fri Feb 28 14:08:39
2014 UTC
+++ /branches/bleeding_edge/src/arm/deoptimizer-arm.cc Mon Mar 3 11:11:39
2014 UTC
@@ -70,13 +70,16 @@
}
}
- // For each LLazyBailout instruction insert a call to the corresponding
- // deoptimization entry.
DeoptimizationInputData* deopt_data =
DeoptimizationInputData::cast(code->deoptimization_data());
+ SharedFunctionInfo* shared =
+ SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
+ shared->EvictFromOptimizedCodeMap(code, "deoptimized code");
#ifdef DEBUG
Address prev_call_address = NULL;
#endif
+ // For each LLazyBailout instruction insert a call to the corresponding
+ // deoptimization entry.
for (int i = 0; i < deopt_data->DeoptCount(); i++) {
if (deopt_data->Pc(i)->value() == -1) continue;
Address call_address = code_start_address + deopt_data->Pc(i)->value();
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Feb 27
17:33:25 2014 UTC
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Mar 3
11:11:39 2014 UTC
@@ -908,6 +908,13 @@
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
+ if (info_->IsOptimizing()) {
+ // Reference to shared function info does not change between phases.
+ AllowDeferredHandleDereference allow_handle_dereference;
+ data->SetSharedFunctionInfo(*info_->shared_info());
+ } else {
+ data->SetSharedFunctionInfo(Smi::FromInt(0));
+ }
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
=======================================
--- /branches/bleeding_edge/src/compiler.cc Fri Feb 28 14:09:52 2014 UTC
+++ /branches/bleeding_edge/src/compiler.cc Mon Mar 3 11:11:39 2014 UTC
@@ -1070,10 +1070,7 @@
}
FixedArray* literals =
shared->GetLiteralsFromOptimizedCodeMap(index);
if (literals != NULL) function->set_literals(literals);
- Handle<Code> code(shared->GetCodeFromOptimizedCodeMap(index));
- if (!code->marked_for_deoptimization()) return code;
-
shared->EvictFromOptimizedCodeMap(function->context()->native_context(),
- "code was already marked for
deopt");
+ return Handle<Code>(shared->GetCodeFromOptimizedCodeMap(index));
}
}
return Handle<Code>::null();
=======================================
--- /branches/bleeding_edge/src/deoptimizer.cc Fri Feb 28 12:27:31 2014 UTC
+++ /branches/bleeding_edge/src/deoptimizer.cc Mon Mar 3 11:11:39 2014 UTC
@@ -342,8 +342,6 @@
// Unlink this function and evict from optimized code map.
SharedFunctionInfo* shared = function->shared();
function->set_code(shared->code());
-
shared->EvictFromOptimizedCodeMap(function->context()->native_context(),
- "deoptimized function");
if (FLAG_trace_deopt) {
CodeTracer::Scope
scope(code->GetHeap()->isolate()->GetCodeTracer());
=======================================
--- /branches/bleeding_edge/src/factory.cc Fri Feb 28 14:09:52 2014 UTC
+++ /branches/bleeding_edge/src/factory.cc Mon Mar 3 11:11:39 2014 UTC
@@ -968,6 +968,7 @@
function_info->GetLiteralsFromOptimizedCodeMap(index);
if (literals != NULL) result->set_literals(literals);
Code* code = function_info->GetCodeFromOptimizedCodeMap(index);
+ ASSERT(!code->marked_for_deoptimization());
result->ReplaceCode(code);
return result;
}
=======================================
--- /branches/bleeding_edge/src/ia32/deoptimizer-ia32.cc Fri Feb 28
12:41:25 2014 UTC
+++ /branches/bleeding_edge/src/ia32/deoptimizer-ia32.cc Mon Mar 3
11:11:39 2014 UTC
@@ -145,9 +145,6 @@
Address reloc_end_address = reloc_info->address() + reloc_info->Size();
RelocInfoWriter reloc_info_writer(reloc_end_address, code_start_address);
- // For each LLazyBailout instruction insert a call to the corresponding
- // deoptimization entry.
-
// Since the call is a relative encoding, write new
// reloc info. We do not need any of the existing reloc info because the
// existing code will not be used again (we zap it in debug builds).
@@ -155,9 +152,14 @@
// Emit call to lazy deoptimization at all lazy deopt points.
DeoptimizationInputData* deopt_data =
DeoptimizationInputData::cast(code->deoptimization_data());
+ SharedFunctionInfo* shared =
+ SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
+ shared->EvictFromOptimizedCodeMap(code, "deoptimized code");
#ifdef DEBUG
Address prev_call_address = NULL;
#endif
+ // For each LLazyBailout instruction insert a call to the corresponding
+ // deoptimization entry.
for (int i = 0; i < deopt_data->DeoptCount(); i++) {
if (deopt_data->Pc(i)->value() == -1) continue;
// Patch lazy deoptimization entry.
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Feb 27
17:33:25 2014 UTC
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Mar 3
11:11:39 2014 UTC
@@ -1180,6 +1180,13 @@
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
+ if (info_->IsOptimizing()) {
+ // Reference to shared function info does not change between phases.
+ AllowDeferredHandleDereference allow_handle_dereference;
+ data->SetSharedFunctionInfo(*info_->shared_info());
+ } else {
+ data->SetSharedFunctionInfo(Smi::FromInt(0));
+ }
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
=======================================
--- /branches/bleeding_edge/src/mips/deoptimizer-mips.cc Fri Feb 28
14:08:39 2014 UTC
+++ /branches/bleeding_edge/src/mips/deoptimizer-mips.cc Mon Mar 3
11:11:39 2014 UTC
@@ -69,13 +69,16 @@
}
}
- // For each LLazyBailout instruction insert a call to the corresponding
- // deoptimization entry.
DeoptimizationInputData* deopt_data =
DeoptimizationInputData::cast(code->deoptimization_data());
+ SharedFunctionInfo* shared =
+ SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
+ shared->EvictFromOptimizedCodeMap(code, "deoptimized code");
#ifdef DEBUG
Address prev_call_address = NULL;
#endif
+ // For each LLazyBailout instruction insert a call to the corresponding
+ // deoptimization entry.
for (int i = 0; i < deopt_data->DeoptCount(); i++) {
if (deopt_data->Pc(i)->value() == -1) continue;
Address call_address = code_start_address + deopt_data->Pc(i)->value();
=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Thu Feb 27
17:33:25 2014 UTC
+++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Mon Mar 3
11:11:39 2014 UTC
@@ -861,6 +861,13 @@
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
+ if (info_->IsOptimizing()) {
+ // Reference to shared function info does not change between phases.
+ AllowDeferredHandleDereference allow_handle_dereference;
+ data->SetSharedFunctionInfo(*info_->shared_info());
+ } else {
+ data->SetSharedFunctionInfo(Smi::FromInt(0));
+ }
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Fri Feb 28 14:09:52 2014 UTC
+++ /branches/bleeding_edge/src/objects-inl.h Mon Mar 3 11:11:39 2014 UTC
@@ -5437,8 +5437,6 @@
if (was_optimized && !is_optimized) {
// TODO(titzer): linear in the number of optimized functions; fix!
context()->native_context()->RemoveOptimizedFunction(this);
- shared()->EvictFromOptimizedCodeMap(context()->native_context(),
- "Removing optimized code");
}
}
=======================================
--- /branches/bleeding_edge/src/objects.cc Fri Feb 28 12:27:31 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc Mon Mar 3 11:11:39 2014 UTC
@@ -9631,46 +9631,42 @@
}
-void SharedFunctionInfo::EvictFromOptimizedCodeMap(Context* context,
+void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
const char* reason) {
- ASSERT(context->IsNativeContext());
if (optimized_code_map()->IsSmi()) return;
+ int i;
+ bool removed_entry = false;
FixedArray* code_map = FixedArray::cast(optimized_code_map());
- int dst = kEntriesStart;
- int length = code_map->length();
- for (int src = kEntriesStart; src < length; src += kEntryLength) {
- Context* context_key = Context::cast(code_map->get(src));
- ASSERT(context->IsNativeContext());
- if (context_key == context) {
+ for (i = kEntriesStart; i < code_map->length(); i += kEntryLength) {
+ ASSERT(code_map->get(i)->IsNativeContext());
+ if (Code::cast(code_map->get(i + 1)) == optimized_code) {
if (FLAG_trace_opt) {
PrintF("[evicting entry from optimizing code map (%s) for ",
reason);
ShortPrint();
- BailoutId osr(Smi::cast(code_map->get(src +
kOsrAstIdOffset))->value());
- if (osr.IsNone()) {
- PrintF("]\n");
- } else {
- PrintF(" (osr ast id %d)]\n", osr.ToInt());
- }
+ PrintF("]\n");
}
- continue;
+ removed_entry = true;
+ break;
}
- if (dst != src) {
- code_map->set(dst + kContextOffset,
- code_map->get(src + kContextOffset));
- code_map->set(dst + kCachedCodeOffset,
- code_map->get(src + kCachedCodeOffset));
- code_map->set(dst + kLiteralsOffset,
- code_map->get(src + kLiteralsOffset));
- code_map->set(dst + kOsrAstIdOffset,
- code_map->get(src + kOsrAstIdOffset));
- }
- dst += kEntryLength;
}
- if (dst != length) {
+ while (i < (code_map->length() - kEntryLength)) {
+ code_map->set(i + kContextOffset,
+ code_map->get(i + kContextOffset + kEntryLength));
+ code_map->set(i + kCachedCodeOffset,
+ code_map->get(i + kCachedCodeOffset + kEntryLength));
+ code_map->set(i + kLiteralsOffset,
+ code_map->get(i + kLiteralsOffset + kEntryLength));
+ code_map->set(i + kOsrAstIdOffset,
+ code_map->get(i + kOsrAstIdOffset + kEntryLength));
+ i += kEntryLength;
+ }
+ if (removed_entry) {
// Always trim even when array is cleared because of heap verifier.
- RightTrimFixedArray<FROM_MUTATOR>(GetHeap(), code_map, length - dst);
- if (code_map->length() == kEntriesStart) ClearOptimizedCodeMap();
+ RightTrimFixedArray<FROM_MUTATOR>(GetHeap(), code_map, kEntryLength);
+ if (code_map->length() == kEntriesStart) {
+ ClearOptimizedCodeMap();
+ }
}
}
=======================================
--- /branches/bleeding_edge/src/objects.h Fri Feb 28 14:09:52 2014 UTC
+++ /branches/bleeding_edge/src/objects.h Mon Mar 3 11:11:39 2014 UTC
@@ -4997,7 +4997,8 @@
static const int kOsrAstIdIndex = 3;
static const int kOsrPcOffsetIndex = 4;
static const int kOptimizationIdIndex = 5;
- static const int kFirstDeoptEntryIndex = 6;
+ static const int kSharedFunctionInfoIndex = 6;
+ static const int kFirstDeoptEntryIndex = 7;
// Offsets of deopt entry elements relative to the start of the entry.
static const int kAstIdRawOffset = 0;
@@ -5021,6 +5022,7 @@
DEFINE_ELEMENT_ACCESSORS(OsrAstId, Smi)
DEFINE_ELEMENT_ACCESSORS(OsrPcOffset, Smi)
DEFINE_ELEMENT_ACCESSORS(OptimizationId, Smi)
+ DEFINE_ELEMENT_ACCESSORS(SharedFunctionInfo, Object)
#undef DEFINE_ELEMENT_ACCESSORS
@@ -6662,9 +6664,8 @@
// Clear optimized code map.
void ClearOptimizedCodeMap();
- // Removed code objects associated to the given native context from
- // the optimized code map.
- void EvictFromOptimizedCodeMap(Context* context, const char* reason);
+ // Removed a specific optimized code object from the optimized code map.
+ void EvictFromOptimizedCodeMap(Code* optimized_code, const char* reason);
// Trims the optimized code map after entries have been removed.
void TrimOptimizedCodeMap(int shrink_by);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Fri Feb 28 12:27:31 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc Mon Mar 3 11:11:39 2014 UTC
@@ -8523,6 +8523,10 @@
PrintF("]\n");
}
function->ReplaceCode(function->shared()->code());
+ // Evict optimized code for this function from the cache so that it
+ // doesn't get used for new closures.
+ function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
+ "notify deoptimized");
}
} else {
// TODO(titzer): we should probably do DeoptimizeCodeList(code)
@@ -8530,10 +8534,6 @@
// If there is an index by shared function info, all the better.
Deoptimizer::DeoptimizeFunction(*function);
}
- // Evict optimized code for this function from the cache so that it
doesn't
- // get used for new closures.
- function->shared()->EvictFromOptimizedCodeMap(
- function->context()->native_context(), "notify deoptimized");
return isolate->heap()->undefined_value();
}
=======================================
--- /branches/bleeding_edge/src/x64/deoptimizer-x64.cc Fri Feb 28 12:41:25
2014 UTC
+++ /branches/bleeding_edge/src/x64/deoptimizer-x64.cc Mon Mar 3 11:11:39
2014 UTC
@@ -83,6 +83,12 @@
#endif
DeoptimizationInputData* deopt_data =
DeoptimizationInputData::cast(code->deoptimization_data());
+ SharedFunctionInfo* shared =
+ SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo());
+ shared->EvictFromOptimizedCodeMap(code, "deoptimized code");
+ deopt_data->SetSharedFunctionInfo(Smi::FromInt(0));
+ // For each LLazyBailout instruction insert a call to the corresponding
+ // deoptimization entry.
for (int i = 0; i < deopt_data->DeoptCount(); i++) {
if (deopt_data->Pc(i)->value() == -1) continue;
// Position where Call will be patched in.
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Feb 27
17:33:25 2014 UTC
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Mar 3
11:11:39 2014 UTC
@@ -793,6 +793,13 @@
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
+ if (info_->IsOptimizing()) {
+ // Reference to shared function info does not change between phases.
+ AllowDeferredHandleDereference allow_handle_dereference;
+ data->SetSharedFunctionInfo(*info_->shared_info());
+ } else {
+ data->SetSharedFunctionInfo(Smi::FromInt(0));
+ }
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Wed Feb 19 13:55:25
2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-heap.cc Mon Mar 3 11:11:39
2014 UTC
@@ -3036,6 +3036,11 @@
TEST(ReleaseStackTraceData) {
+ if (i::FLAG_always_opt) {
+ // TODO(ulan): Remove this once the memory leak via code_next_link is
fixed.
+ // See: https://codereview.chromium.org/181833004/
+ return;
+ }
FLAG_use_ic = false; // ICs retain objects.
FLAG_concurrent_recompilation = false;
CcTest::InitializeVM();
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.