Index: src/debug/debug.cc |
diff --git a/src/debug/debug.cc b/src/debug/debug.cc |
index 06da2f8cbe2f0ed9f32c4ab5f84dacffc077b288..93c914c3f8db222ad54144a285caebc476d99c9b 100644 |
--- a/src/debug/debug.cc |
+++ b/src/debug/debug.cc |
@@ -1240,12 +1240,17 @@ class RedirectActiveFunctions : public ThreadVisitor { |
for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) { |
JavaScriptFrame* frame = it.frame(); |
JSFunction* function = frame->function(); |
+ if (frame->is_optimized()) continue; |
+ if (!function->Inlines(shared_)) continue; |
+ |
if (frame->is_interpreted()) { |
- // TODO(yangguo): replace dispatch table for activated frames. |
+ InterpretedFrame* interpreted_frame = |
+ reinterpret_cast<InterpretedFrame*>(frame); |
+ BytecodeArray* debug_copy = |
+ shared_->GetDebugInfo()->abstract_code()->GetBytecodeArray(); |
+ interpreted_frame->PatchBytecodeArray(debug_copy); |
continue; |
} |
- if (frame->is_optimized()) continue; |
- if (!function->Inlines(shared_)) continue; |
Code* frame_code = frame->LookupCode(); |
DCHECK(frame_code->kind() == Code::FUNCTION); |
@@ -1304,11 +1309,15 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) { |
// Make sure we abort incremental marking. |
isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, |
"prepare for break points"); |
+ bool is_interpreted = shared->HasBytecodeArray(); |
{ |
+ // TODO(yangguo): with bytecode, we still walk the heap to find all |
+ // optimized code for the function to deoptimize. We can probably be |
+ // smarter here and avoid the heap walk. |
HeapIterator iterator(isolate_->heap()); |
HeapObject* obj; |
- bool include_generators = shared->is_generator(); |
+ bool include_generators = !is_interpreted && shared->is_generator(); |
while ((obj = iterator.next())) { |
if (obj->IsJSFunction()) { |
@@ -1317,6 +1326,7 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) { |
if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) { |
Deoptimizer::DeoptimizeFunction(function); |
} |
+ if (is_interpreted) continue; |
if (function->shared() == *shared) functions.Add(handle(function)); |
} else if (include_generators && obj->IsJSGeneratorObject()) { |
JSGeneratorObject* generator_obj = JSGeneratorObject::cast(obj); |
@@ -1332,7 +1342,12 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) { |
} |
} |
- if (!shared->HasDebugCode()) { |
+ // We do not need to replace code to debug bytecode. |
+ DCHECK(!is_interpreted || functions.length() == 0); |
+ DCHECK(!is_interpreted || suspended_generators.length() == 0); |
+ |
+ // We do not need to recompile to debug bytecode. |
+ if (!is_interpreted && !shared->HasDebugCode()) { |
DCHECK(functions.length() > 0); |
if (!Compiler::CompileDebugCode(functions.first())) return false; |
} |
@@ -1503,10 +1518,16 @@ bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, |
return false; |
} |
- if (!PrepareFunctionForBreakPoints(shared)) return false; |
- |
- CreateDebugInfo(shared); |
- |
+ if (shared->HasBytecodeArray()) { |
+ // To prepare bytecode for debugging, we already need to have the debug |
+ // info (containing the debug copy) upfront, but since we do not recompile, |
+ // preparing for break points cannot fail. |
+ CreateDebugInfo(shared); |
+ CHECK(PrepareFunctionForBreakPoints(shared)); |
+ } else { |
+ if (!PrepareFunctionForBreakPoints(shared)) return false; |
+ CreateDebugInfo(shared); |
+ } |
return true; |
} |