Index: src/liveedit.cc |
diff --git a/src/liveedit.cc b/src/liveedit.cc |
index e6bb4b29a636297d25d1d69c9ca7ff3a7b1edb52..01585772ae504466182c9e5e1726e9698220fdb1 100644 |
--- a/src/liveedit.cc |
+++ b/src/liveedit.cc |
@@ -1682,11 +1682,6 @@ static const char* DropFrames(Vector<StackFrame*> frames, |
} |
-static bool IsDropableFrame(StackFrame* frame) { |
- return !frame->is_exit(); |
-} |
- |
- |
// Describes a set of call frames that execute any of listed functions. |
// Finding no such frames does not mean error. |
class MultipleFunctionTarget { |
@@ -1740,12 +1735,20 @@ static const char* DropActivationsInActiveThreadImpl( |
bool target_frame_found = false; |
int bottom_js_frame_index = top_frame_index; |
- bool c_code_found = false; |
+ bool non_droppable_frame_found = false; |
+ LiveEdit::FunctionPatchabilityStatus non_droppable_reason; |
for (; frame_index < frames.length(); frame_index++) { |
StackFrame* frame = frames[frame_index]; |
- if (!IsDropableFrame(frame)) { |
- c_code_found = true; |
+ if (frame->is_exit()) { |
+ non_droppable_frame_found = true; |
+ non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE; |
+ break; |
+ } |
+ if (frame->is_java_script() && |
+ JavaScriptFrame::cast(frame)->function()->shared()->is_generator()) { |
+ non_droppable_frame_found = true; |
+ non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR; |
break; |
} |
if (target.MatchActivation( |
@@ -1755,15 +1758,15 @@ static const char* DropActivationsInActiveThreadImpl( |
} |
} |
- if (c_code_found) { |
- // There is a C frames on stack. Check that there are no target frames |
- // below them. |
+ if (non_droppable_frame_found) { |
+ // There is a C or generator frame on stack. We can't drop C frames, and we |
+ // can't restart generators. Check that there are no target frames below |
+ // them. |
for (; frame_index < frames.length(); frame_index++) { |
StackFrame* frame = frames[frame_index]; |
if (frame->is_java_script()) { |
- if (target.MatchActivation( |
- frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) { |
- // Cannot drop frame under C frames. |
+ if (target.MatchActivation(frame, non_droppable_reason)) { |
+ // Fail. |
return NULL; |
} |
} |
@@ -1833,6 +1836,47 @@ static const char* DropActivationsInActiveThread( |
} |
+bool LiveEdit::FindActiveGenerators(Handle<FixedArray> shared_info_array, |
+ Handle<FixedArray> result, |
+ int len) { |
+ Isolate* isolate = shared_info_array->GetIsolate(); |
+ Heap* heap = isolate->heap(); |
+ heap->EnsureHeapIsIterable(); |
+ bool found_suspended_activations = false; |
+ |
+ ASSERT_LE(len, result->length()); |
+ |
+ DisallowHeapAllocation no_allocation; |
+ |
+ FunctionPatchabilityStatus active = FUNCTION_BLOCKED_ACTIVE_GENERATOR; |
+ |
+ HeapIterator iterator(heap); |
+ HeapObject* obj = NULL; |
+ while ((obj = iterator.next()) != NULL) { |
+ if (!obj->IsJSGeneratorObject()) continue; |
+ |
+ JSGeneratorObject* gen = JSGeneratorObject::cast(obj); |
+ if (gen->is_closed()) continue; |
+ |
+ HandleScope scope(isolate); |
+ |
+ for (int i = 0; i < len; i++) { |
+ Handle<JSValue> jsvalue = |
+ Handle<JSValue>::cast(FixedArray::get(shared_info_array, i)); |
+ Handle<SharedFunctionInfo> shared = |
+ UnwrapSharedFunctionInfoFromJSValue(jsvalue); |
+ |
+ if (gen->function()->shared() == *shared) { |
+ result->set(i, Smi::FromInt(active)); |
+ found_suspended_activations = true; |
+ } |
+ } |
+ } |
+ |
+ return found_suspended_activations; |
+} |
+ |
+ |
class InactiveThreadActivationsChecker : public ThreadVisitor { |
public: |
InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array, |
@@ -1863,18 +1907,29 @@ Handle<JSArray> LiveEdit::CheckAndDropActivations( |
Isolate* isolate = shared_info_array->GetIsolate(); |
int len = GetArrayLength(shared_info_array); |
+ CHECK(shared_info_array->HasFastElements()); |
+ Handle<FixedArray> shared_info_array_elements( |
+ FixedArray::cast(shared_info_array->elements())); |
+ |
Handle<JSArray> result = isolate->factory()->NewJSArray(len); |
+ Handle<FixedArray> result_elements = |
+ JSObject::EnsureWritableFastElements(result); |
// Fill the default values. |
for (int i = 0; i < len; i++) { |
- SetElementSloppy( |
- result, |
- i, |
- Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH), isolate)); |
+ FunctionPatchabilityStatus status = FUNCTION_AVAILABLE_FOR_PATCH; |
+ result_elements->set(i, Smi::FromInt(status)); |
} |
+ // Scan the heap for active generators -- those that are either currently |
+ // running (as we wouldn't want to restart them, because we don't know where |
+ // to restart them from) or suspended. Fail if any one corresponds to the set |
+ // of functions being edited. |
+ if (FindActiveGenerators(shared_info_array_elements, result_elements, len)) { |
+ return result; |
+ } |
- // First check inactive threads. Fail if some functions are blocked there. |
+ // Check inactive threads. Fail if some functions are blocked there. |
InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array, |
result); |
isolate->thread_manager()->IterateArchivedThreads( |
@@ -1937,6 +1992,9 @@ const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) { |
if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) { |
return "Function is blocked under native code"; |
} |
+ if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR) { |
+ return "Function is blocked under a generator activation"; |
+ } |
return NULL; |
} |