Fix FindSharedFunctionInfoInScript to not optimize.

This prevents a corner case in FindSharedFunctionInfoInScript that would cause
functions to be optimized because an intermittent GC would clear the flag
indicating whether breakpoints are present. Above method was also moved into the
Debug class because it is only used by the debugger.

R=verwaest@chromium.org

Review URL: https://chromiumcodereview.appspot.com/10914065

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12428 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 996c84fb
...@@ -936,7 +936,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, ...@@ -936,7 +936,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
// If the debugger requests compilation for break points, we cannot be // If the debugger requests compilation for break points, we cannot be
// aggressive about lazy compilation, because it might trigger compilation // aggressive about lazy compilation, because it might trigger compilation
// of functions without an outer context when setting a breakpoint through // of functions without an outer context when setting a breakpoint through
// Runtime::FindSharedFunctionInfoInScript. // Debug::FindSharedFunctionInfoInScript.
bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext(); bool allow_lazy_without_ctx = literal->AllowsLazyCompilationWithoutContext();
bool allow_lazy = literal->AllowsLazyCompilation() && bool allow_lazy = literal->AllowsLazyCompilation() &&
!LiveEditFunctionTracker::IsActive(info.isolate()) && !LiveEditFunctionTracker::IsActive(info.isolate()) &&
......
...@@ -698,7 +698,7 @@ void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) { ...@@ -698,7 +698,7 @@ void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
// We need to clear all breakpoints associated with the function to restore // We need to clear all breakpoints associated with the function to restore
// original code and avoid patching the code twice later because // original code and avoid patching the code twice later because
// the function will live in the heap until next gc, and can be found by // the function will live in the heap until next gc, and can be found by
// Runtime::FindSharedFunctionInfoInScript. // Debug::FindSharedFunctionInfoInScript.
BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
it.ClearAllDebugBreak(); it.ClearAllDebugBreak();
debug->RemoveDebugInfo(node->debug_info()); debug->RemoveDebugInfo(node->debug_info());
...@@ -1172,11 +1172,10 @@ bool Debug::SetBreakPointForScript(Handle<Script> script, ...@@ -1172,11 +1172,10 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
int* source_position) { int* source_position) {
HandleScope scope(isolate_); HandleScope scope(isolate_);
// No need to call PrepareForBreakPoints because it will be called PrepareForBreakPoints();
// implicitly by Runtime::FindSharedFunctionInfoInScript.
Object* result = Runtime::FindSharedFunctionInfoInScript(isolate_, // Obtain shared function info for the function.
script, Object* result = FindSharedFunctionInfoInScript(script, *source_position);
*source_position);
if (result->IsUndefined()) return false; if (result->IsUndefined()) return false;
// Make sure the function has set up the debug info. // Make sure the function has set up the debug info.
...@@ -2092,6 +2091,115 @@ void Debug::PrepareForBreakPoints() { ...@@ -2092,6 +2091,115 @@ void Debug::PrepareForBreakPoints() {
} }
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;
while (!done) {
{ // Extra scope for iterator and no-allocation.
isolate_->heap()->EnsureHeapIsIterable();
AssertNoAllocation no_alloc_during_heap_iteration;
HeapIterator iterator;
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());
ASSERT(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.
if (target.is_null()) {
return isolate_->heap()->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::BuildFunctionInfo checks whether the
// debugger is active.
if (target_function.is_null()) {
SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
} else {
JSFunction::CompileLazy(target_function, KEEP_EXCEPTION);
}
}
} // End while loop.
return *target;
}
// Ensures the debug information is present for shared. // Ensures the debug information is present for shared.
bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
Handle<JSFunction> function) { Handle<JSFunction> function) {
......
...@@ -257,6 +257,9 @@ class Debug { ...@@ -257,6 +257,9 @@ class Debug {
void PrepareForBreakPoints(); void PrepareForBreakPoints();
// This function is used in FunctionNameUsing* tests.
Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position);
// Returns whether the operation succeeded. Compilation can only be triggered // Returns whether the operation succeeded. Compilation can only be triggered
// if a valid closure is passed as the second argument, otherwise the shared // if a valid closure is passed as the second argument, otherwise the shared
// function needs to be compiled already. // function needs to be compiled already.
......
...@@ -11421,115 +11421,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) { ...@@ -11421,115 +11421,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
} }
Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
Handle<Script> script,
int position) {
// 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.
isolate->debug()->PrepareForBreakPoints();
// 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.
bool done = false;
// The current candidate for the source position:
int target_start_position = RelocInfo::kNoPosition;
Handle<JSFunction> target_function;
Handle<SharedFunctionInfo> target;
while (!done) {
{ // Extra scope for iterator and no-allocation.
isolate->heap()->EnsureHeapIsIterable();
AssertNoAllocation no_alloc_during_heap_iteration;
HeapIterator iterator;
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());
ASSERT(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.
if (target.is_null()) {
return isolate->heap()->undefined_value();
}
// 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::BuildFunctionInfo checks whether the
// debugger is active.
if (target_function.is_null()) {
SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
} else {
JSFunction::CompileLazy(target_function, KEEP_EXCEPTION);
}
}
} // End while loop.
return *target;
}
// Set a break point in a function. // Set a break point in a function.
// args[0]: function // args[0]: function
// args[1]: number: break source position (within the function source) // args[1]: number: break source position (within the function source)
......
...@@ -696,11 +696,6 @@ class Runtime : public AllStatic { ...@@ -696,11 +696,6 @@ class Runtime : public AllStatic {
Handle<Object> object, Handle<Object> object,
Handle<Object> key); Handle<Object> key);
// This function is used in FunctionNameUsing* tests.
static Object* FindSharedFunctionInfoInScript(Isolate* isolate,
Handle<Script> script,
int position);
// Helper functions used stubs. // Helper functions used stubs.
static void PerformGC(Object* result); static void PerformGC(Object* result);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "v8.h" #include "v8.h"
#include "api.h" #include "api.h"
#include "debug.h"
#include "runtime.h" #include "runtime.h"
#include "cctest.h" #include "cctest.h"
...@@ -87,10 +88,10 @@ static void CheckFunctionName(v8::Handle<v8::Script> script, ...@@ -87,10 +88,10 @@ static void CheckFunctionName(v8::Handle<v8::Script> script,
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
// Obtain SharedFunctionInfo for the function. // Obtain SharedFunctionInfo for the function.
Isolate::Current()->debug()->PrepareForBreakPoints();
Object* shared_func_info_ptr = Object* shared_func_info_ptr =
Runtime::FindSharedFunctionInfoInScript(Isolate::Current(), Isolate::Current()->debug()->FindSharedFunctionInfoInScript(i_script,
i_script, func_pos);
func_pos);
CHECK(shared_func_info_ptr != HEAP->undefined_value()); CHECK(shared_func_info_ptr != HEAP->undefined_value());
Handle<SharedFunctionInfo> shared_func_info( Handle<SharedFunctionInfo> shared_func_info(
SharedFunctionInfo::cast(shared_func_info_ptr)); SharedFunctionInfo::cast(shared_func_info_ptr));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment