Chromium Code Reviews| Index: src/liveedit.cc |
| diff --git a/src/liveedit.cc b/src/liveedit.cc |
| index e4d35d650fc285feac9eef2f4cfaf8b3aef21e1e..1df4729e69515ff04fe55bb002f6b06442940bde 100644 |
| --- a/src/liveedit.cc |
| +++ b/src/liveedit.cc |
| @@ -1655,11 +1655,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 { |
| @@ -1713,12 +1708,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()) continue; |
| + if (JavaScriptFrame::cast(frame)->function()->shared()->is_generator()) { |
| + non_droppable_frame_found = true; |
| + non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR; |
| break; |
| } |
| if (target.MatchActivation( |
| @@ -1728,15 +1731,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; |
| } |
| } |
| @@ -1806,6 +1809,46 @@ static const char* DropActivationsInActiveThread( |
| } |
| +bool LiveEdit::FindActiveGenerators(Handle<FixedArray> shared_info_array, |
| + Handle<FixedArray> result, int len) { |
|
Yang
2014/05/06 13:05:03
one argument per line is easier on the eye.
|
| + 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)) { |
|
Yang
2014/05/06 13:05:03
I think we can remove one set of brackets here.
|
| + 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, |
| @@ -1836,18 +1879,28 @@ 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)) |
|
Yang
2014/05/06 13:05:03
please use curly brackets if the if-statement cont
|
| + 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( |
| @@ -1910,6 +1963,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; |
| } |