VMState<COMPILER> state(info.isolate());
// Get rid of old list of shared function infos.
- script->set_shared_function_infos(Smi::FromInt(0));
-
+ info.MarkAsFirstCompile();
info.parse_info()->set_global();
if (!Parser::ParseStatic(info.parse_info())) return;
FunctionLiteral* literal, Handle<Script> script,
CompilationInfo* outer_info) {
// Precondition: code has been parsed and scopes have been analyzed.
+ Isolate* isolate = outer_info->isolate();
MaybeHandle<SharedFunctionInfo> maybe_existing;
if (outer_info->is_first_compile()) {
// On the first compile, there are no existing shared function info for
- // inner functions yet, so do not try to find them.
- DCHECK(script->FindSharedFunctionInfo(literal).is_null());
+ // inner functions yet, so do not try to find them. All bets are off for
+ // live edit though.
+ DCHECK(script->FindSharedFunctionInfo(literal).is_null() ||
+ isolate->debug()->live_edit_enabled());
} else {
maybe_existing = script->FindSharedFunctionInfo(literal);
}
if (outer_info->will_serialize()) info.PrepareForSerializing();
if (outer_info->is_first_compile()) info.MarkAsFirstCompile();
- Isolate* isolate = info.isolate();
- Factory* factory = isolate->factory();
LiveEditFunctionTracker live_edit_tracker(isolate, literal);
// Determine if the function can be lazily compiled. This is necessary to
// allow some of our builtin JS files to be lazily compiled. These
if (maybe_existing.is_null()) {
// Create a shared function info object.
- Handle<SharedFunctionInfo> result = factory->NewSharedFunctionInfo(
- literal->name(), literal->materialized_literal_count(), literal->kind(),
- info.code(), scope_info, info.feedback_vector());
+ Handle<SharedFunctionInfo> result =
+ isolate->factory()->NewSharedFunctionInfo(
+ literal->name(), literal->materialized_literal_count(),
+ literal->kind(), info.code(), scope_info, info.feedback_vector());
SharedFunctionInfo::InitFromFunctionLiteral(result, literal);
SharedFunctionInfo::SetScript(result, script);
}
-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);
+ 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;
+ 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;
+ }
+ 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();
}