| Index: src/debug.cc
|
| diff --git a/src/debug.cc b/src/debug.cc
|
| index fefccc893ffe03c145a933c982a3f3488fcf3d01..f814db84868032201feebecc059560e810a7bcd4 100644
|
| --- a/src/debug.cc
|
| +++ b/src/debug.cc
|
| @@ -1984,125 +1984,126 @@
|
| }
|
|
|
|
|
| -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 (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;
|
| - }
|
| - }
|
| -
|
| - 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_;
|
| -};
|
| -
|
| -
|
| -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);
|
| - 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);
|
| - }
|
| - // If not, compile to reveal inner functions, if possible.
|
| - if (shared->allows_lazy_compilation_without_context()) {
|
| - if (!CompileToRevealInnerFunctions(shared)) break;
|
| - continue;
|
| - }
|
| -
|
| - // 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;
|
| - SharedFunctionInfo* shared = NULL;
|
| - 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;
|
| + // 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 (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();
|
| + 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.
|
| +
|
| + if (target.is_null()) return isolate_->factory()->undefined_value();
|
| +
|
| + // There will be at least one break point when we are done.
|
| + has_break_points_ = true;
|
| +
|
| + // 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();
|
| + }
|
| + } // 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);
|
| + }
|
| + }
|
| +
|
| + return target;
|
| }
|
|
|
|
|
|
|