Index: src/debug.cc |
diff --git a/src/debug.cc b/src/debug.cc |
index f814db84868032201feebecc059560e810a7bcd4..fefccc893ffe03c145a933c982a3f3488fcf3d01 100644 |
--- a/src/debug.cc |
+++ b/src/debug.cc |
@@ -1984,126 +1984,125 @@ void Debug::PrepareForBreakPoints() { |
} |
-Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, |
- int position) { |
- // Iterate the heap looking for SharedFunctionInfo generated from the |
- // script. The inner most SharedFunctionInfo containing the source position |
- // for the requested break point is found. |
- // NOTE: This might require several heap iterations. If the SharedFunctionInfo |
- // which is found is not compiled it is compiled and the heap is iterated |
- // again as the compilation might create inner functions from the newly |
- // compiled function and the actual requested break point might be in one of |
- // these functions. |
- // NOTE: The below fix-point iteration depends on all functions that cannot be |
- // compiled lazily without a context to not be compiled at all. Compilation |
- // will be triggered at points where we do not need a context. |
- bool done = false; |
- // The current candidate for the source position: |
- int target_start_position = RelocInfo::kNoPosition; |
- Handle<JSFunction> target_function; |
- Handle<SharedFunctionInfo> target; |
- Heap* heap = isolate_->heap(); |
- while (!done) { |
- { // Extra scope for iterator. |
- // If lazy compilation is off, we won't have duplicate shared function |
- // infos that need to be filtered. |
- HeapIterator iterator(heap, FLAG_lazy ? HeapIterator::kNoFiltering |
- : HeapIterator::kFilterUnreachable); |
- for (HeapObject* obj = iterator.next(); |
- obj != NULL; obj = iterator.next()) { |
- bool found_next_candidate = false; |
- Handle<JSFunction> function; |
- Handle<SharedFunctionInfo> shared; |
- if (obj->IsJSFunction()) { |
- function = Handle<JSFunction>(JSFunction::cast(obj)); |
- shared = Handle<SharedFunctionInfo>(function->shared()); |
- DCHECK(shared->allows_lazy_compilation() || shared->is_compiled()); |
- found_next_candidate = true; |
- } else if (obj->IsSharedFunctionInfo()) { |
- shared = Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(obj)); |
- // Skip functions that we cannot compile lazily without a context, |
- // which is not available here, because there is no closure. |
- found_next_candidate = shared->is_compiled() || |
- shared->allows_lazy_compilation_without_context(); |
- } |
- if (!found_next_candidate) continue; |
- if (shared->script() == *script) { |
- // If the SharedFunctionInfo found has the requested script data and |
- // contains the source position it is a candidate. |
- int start_position = shared->function_token_position(); |
- if (start_position == RelocInfo::kNoPosition) { |
- start_position = shared->start_position(); |
- } |
- if (start_position <= position && |
- position <= shared->end_position()) { |
- // If there is no candidate or this function is within the current |
- // candidate this is the new candidate. |
- if (target.is_null()) { |
- target_start_position = start_position; |
- target_function = function; |
- target = shared; |
- } else { |
- if (target_start_position == start_position && |
- shared->end_position() == target->end_position()) { |
- // If a top-level function contains only one function |
- // declaration the source for the top-level and the function |
- // is the same. In that case prefer the non top-level function. |
- if (!shared->is_toplevel()) { |
- target_start_position = start_position; |
- target_function = function; |
- target = shared; |
- } |
- } else if (target_start_position <= start_position && |
- shared->end_position() <= target->end_position()) { |
- // This containment check includes equality as a function |
- // inside a top-level function can share either start or end |
- // position with the top-level function. |
- target_start_position = start_position; |
- target_function = function; |
- target = shared; |
- } |
- } |
- } |
- } |
- } // End for loop. |
- } // End no-allocation scope. |
+class SharedFunctionInfoFinder { |
+ public: |
+ explicit SharedFunctionInfoFinder(int target_position) |
+ : current_candidate_(NULL), |
+ current_candidate_closure_(NULL), |
+ current_start_position_(RelocInfo::kNoPosition), |
+ target_position_(target_position) {} |
+ |
+ void NewCandidate(SharedFunctionInfo* shared, JSFunction* closure = NULL) { |
+ int start_position = shared->function_token_position(); |
+ if (start_position == RelocInfo::kNoPosition) { |
+ start_position = shared->start_position(); |
+ } |
- if (target.is_null()) return isolate_->factory()->undefined_value(); |
+ if (start_position > target_position_) return; |
+ if (target_position_ > shared->end_position()) return; |
+ |
+ if (current_candidate_ != NULL) { |
+ if (current_start_position_ == start_position && |
+ shared->end_position() == current_candidate_->end_position()) { |
+ // If a top-level function contains only one function |
+ // declaration the source for the top-level and the function |
+ // is the same. In that case prefer the non top-level function. |
+ if (shared->is_toplevel()) return; |
+ } else if (start_position < current_start_position_ || |
+ current_candidate_->end_position() < shared->end_position()) { |
+ return; |
+ } |
+ } |
- // There will be at least one break point when we are done. |
- has_break_points_ = true; |
+ current_start_position_ = start_position; |
+ current_candidate_ = shared; |
+ current_candidate_closure_ = closure; |
+ } |
+ |
+ SharedFunctionInfo* Result() { return current_candidate_; } |
+ |
+ JSFunction* ResultClosure() { return current_candidate_closure_; } |
+ |
+ private: |
+ SharedFunctionInfo* current_candidate_; |
+ JSFunction* current_candidate_closure_; |
+ int current_start_position_; |
+ int target_position_; |
+ DisallowHeapAllocation no_gc_; |
+}; |
- // If the candidate found is compiled we are done. |
- done = target->is_compiled(); |
- if (!done) { |
- // If the candidate is not compiled, compile it to reveal any inner |
- // functions which might contain the requested source position. This |
- // will compile all inner functions that cannot be compiled without a |
- // context, because Compiler::GetSharedFunctionInfo checks whether the |
- // debugger is active. |
- MaybeHandle<Code> maybe_result = target_function.is_null() |
- ? Compiler::GetUnoptimizedCode(target) |
- : Compiler::GetUnoptimizedCode(target_function); |
- if (maybe_result.is_null()) return isolate_->factory()->undefined_value(); |
+ |
+template <typename C> |
+bool Debug::CompileToRevealInnerFunctions(C* compilable) { |
+ HandleScope scope(isolate_); |
+ // Force compiling inner functions that require context. |
+ // TODO(yangguo): remove this hack. |
+ bool has_break_points = has_break_points_; |
+ has_break_points_ = true; |
+ Handle<C> compilable_handle(compilable); |
+ bool result = !Compiler::GetUnoptimizedCode(compilable_handle).is_null(); |
+ has_break_points_ = has_break_points; |
+ return result; |
+} |
+ |
+ |
+Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, |
+ int position) { |
+ while (true) { |
+ // Go through all shared function infos associated with this script to |
+ // find the inner most function containing this position. |
+ if (!script->shared_function_infos()->IsWeakFixedArray()) break; |
+ WeakFixedArray* array = |
+ WeakFixedArray::cast(script->shared_function_infos()); |
+ |
+ SharedFunctionInfo* shared; |
+ { |
+ SharedFunctionInfoFinder finder(position); |
+ for (int i = 0; i < array->Length(); i++) { |
+ Object* item = array->Get(i); |
+ if (!item->IsSharedFunctionInfo()) continue; |
+ SharedFunctionInfo* shared = SharedFunctionInfo::cast(item); |
brucedawson
2015/06/29 17:08:53
Is it intentional that this shadows the outer-scop
|
+ finder.NewCandidate(shared); |
+ } |
+ shared = finder.Result(); |
+ if (shared == NULL) break; |
+ // We found it if it's already compiled. |
+ if (shared->is_compiled()) return handle(shared); |
} |
- } // End while loop. |
- |
- // JSFunctions from the same literal may not have the same shared function |
- // info. Find those JSFunctions and deduplicate the shared function info. |
- HeapIterator iterator(heap, FLAG_lazy ? HeapIterator::kNoFiltering |
- : HeapIterator::kFilterUnreachable); |
- for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
- if (!obj->IsJSFunction()) continue; |
- JSFunction* function = JSFunction::cast(obj); |
- SharedFunctionInfo* shared = function->shared(); |
- if (shared != *target && shared->script() == target->script() && |
- shared->start_position_and_type() == |
- target->start_position_and_type()) { |
- function->set_shared(*target); |
+ // If not, compile to reveal inner functions, if possible. |
+ if (shared->allows_lazy_compilation_without_context()) { |
+ if (!CompileToRevealInnerFunctions(shared)) break; |
+ continue; |
} |
- } |
- return target; |
+ // If not possible, comb the heap for the best suitable compile target. |
+ JSFunction* closure; |
+ { |
+ HeapIterator it(isolate_->heap(), HeapIterator::kNoFiltering); |
+ SharedFunctionInfoFinder finder(position); |
+ while (HeapObject* object = it.next()) { |
+ JSFunction* closure = NULL; |
brucedawson
2015/06/29 17:08:53
Is it intentional that this shadows the outer-scop
|
+ SharedFunctionInfo* shared = NULL; |
brucedawson
2015/06/29 17:08:53
Is it intentional that this shadows the outer-scop
|
+ if (object->IsJSFunction()) { |
+ closure = JSFunction::cast(object); |
+ shared = closure->shared(); |
+ } else if (object->IsSharedFunctionInfo()) { |
+ shared = SharedFunctionInfo::cast(object); |
+ if (!shared->allows_lazy_compilation_without_context()) continue; |
+ } else { |
+ continue; |
+ } |
+ if (shared->script() == *script) finder.NewCandidate(shared, closure); |
+ } |
+ closure = finder.ResultClosure(); |
+ shared = finder.Result(); |
+ } |
+ if (closure == NULL ? !CompileToRevealInnerFunctions(shared) |
+ : !CompileToRevealInnerFunctions(closure)) { |
+ break; |
+ } |
+ } |
+ return isolate_->factory()->undefined_value(); |
} |