// 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;
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);
}
}
- // 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();
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);
}
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();
// 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());
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;
}
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).
// 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.
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);
}
}
- // 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();
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);
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");
}
}
}
-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;
- }
- 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));
+ removed_entry = true;
+ break;
}
- 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();
+ }
}
}
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;
DEFINE_ELEMENT_ACCESSORS(OsrAstId, Smi)
DEFINE_ELEMENT_ACCESSORS(OsrPcOffset, Smi)
DEFINE_ELEMENT_ACCESSORS(OptimizationId, Smi)
+ DEFINE_ELEMENT_ACCESSORS(SharedFunctionInfo, Object)
#undef DEFINE_ELEMENT_ACCESSORS
// 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);
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)
// 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();
}
#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.
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);
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();
--- /dev/null
+// 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());