summaryrefslogtreecommitdiff
path: root/chromium/v8/src/debug.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/debug.cc')
-rw-r--r--chromium/v8/src/debug.cc611
1 files changed, 269 insertions, 342 deletions
diff --git a/chromium/v8/src/debug.cc b/chromium/v8/src/debug.cc
index 89334fa7086..e952fe7ebb8 100644
--- a/chromium/v8/src/debug.cc
+++ b/chromium/v8/src/debug.cc
@@ -48,7 +48,7 @@ Debug::Debug(Isolate* isolate)
}
-static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
+static v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
// Isolate::context() may have been NULL when "script collected" event
// occured.
@@ -58,6 +58,21 @@ static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
}
+BreakLocation::BreakLocation(Handle<DebugInfo> debug_info, RelocInfo* rinfo,
+ RelocInfo* original_rinfo, int position,
+ int statement_position)
+ : debug_info_(debug_info),
+ pc_offset_(static_cast<int>(rinfo->pc() - debug_info->code()->entry())),
+ original_pc_offset_(static_cast<int>(
+ original_rinfo->pc() - debug_info->original_code()->entry())),
+ rmode_(rinfo->rmode()),
+ original_rmode_(original_rinfo->rmode()),
+ data_(rinfo->data()),
+ original_data_(original_rinfo->data()),
+ position_(position),
+ statement_position_(statement_position) {}
+
+
BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info,
BreakLocatorType type)
: debug_info_(debug_info),
@@ -99,6 +114,7 @@ void BreakLocation::Iterator::Next() {
debug_info_->shared()->start_position());
DCHECK(position_ >= 0);
DCHECK(statement_position_ >= 0);
+ continue;
}
// Check for break at return.
@@ -112,7 +128,7 @@ void BreakLocation::Iterator::Next() {
}
statement_position_ = position_;
break_index_++;
- return;
+ break;
}
if (RelocInfo::IsCodeTarget(rmode())) {
@@ -124,32 +140,28 @@ void BreakLocation::Iterator::Next() {
if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) {
break_index_++;
- return;
+ break;
}
- // Skip below if we only want locations for calls and returns.
- if (type_ == CALLS_AND_RETURNS) continue;
-
- if ((code->is_inline_cache_stub() && !code->is_binary_op_stub() &&
- !code->is_compare_ic_stub() && !code->is_to_boolean_ic_stub())) {
+ if (code->kind() == Code::STUB &&
+ CodeStub::GetMajorKey(code) == CodeStub::CallFunction) {
break_index_++;
- return;
- }
- if (code->kind() == Code::STUB) {
- if (RelocInfo::IsDebuggerStatement(rmode())) {
- break_index_++;
- return;
- } else if (CodeStub::GetMajorKey(code) == CodeStub::CallFunction) {
- break_index_++;
- return;
- }
+ break;
}
}
+ // Skip below if we only want locations for calls and returns.
+ if (type_ == CALLS_AND_RETURNS) continue;
+
+ if (RelocInfo::IsDebuggerStatement(rmode())) {
+ break_index_++;
+ break;
+ }
+
if (RelocInfo::IsDebugBreakSlot(rmode()) && type_ != CALLS_AND_RETURNS) {
// There is always a possible break point at a debug break slot.
break_index_++;
- return;
+ break;
}
}
}
@@ -232,6 +244,7 @@ BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info,
void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) {
// If there is not already a real break point here patch code with debug
// break.
+ DCHECK(code()->has_debug_break_slots());
if (!HasBreakPoint()) SetDebugBreak();
DCHECK(IsDebugBreak() || IsDebuggerStatement());
// Set the break point information.
@@ -363,28 +376,8 @@ static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) {
// Find the builtin debug break function matching the calling convention
// used by the call site.
if (code->is_inline_cache_stub()) {
- switch (code->kind()) {
- case Code::CALL_IC:
- return isolate->builtins()->CallICStub_DebugBreak();
-
- case Code::LOAD_IC:
- return isolate->builtins()->LoadIC_DebugBreak();
-
- case Code::STORE_IC:
- return isolate->builtins()->StoreIC_DebugBreak();
-
- case Code::KEYED_LOAD_IC:
- return isolate->builtins()->KeyedLoadIC_DebugBreak();
-
- case Code::KEYED_STORE_IC:
- return isolate->builtins()->KeyedStoreIC_DebugBreak();
-
- case Code::COMPARE_NIL_IC:
- return isolate->builtins()->CompareNilIC_DebugBreak();
-
- default:
- UNREACHABLE();
- }
+ DCHECK(code->kind() == Code::CALL_IC);
+ return isolate->builtins()->CallICStub_DebugBreak();
}
if (RelocInfo::IsConstructCall(mode)) {
if (code->has_function_cache()) {
@@ -493,101 +486,63 @@ int Debug::ArchiveSpacePerThread() {
}
-ScriptCache::ScriptCache(Isolate* isolate) : HashMap(HashMap::PointersMatch),
- isolate_(isolate) {
+ScriptCache::ScriptCache(Isolate* isolate) : isolate_(isolate) {
Heap* heap = isolate_->heap();
HandleScope scope(isolate_);
+ DCHECK(isolate_->debug()->is_active());
+
// Perform a GC to get rid of all unreferenced scripts.
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptCache");
// Scan heap for Script objects.
- HeapIterator iterator(heap);
- DisallowHeapAllocation no_allocation;
-
- for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
- if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
- Add(Handle<Script>(Script::cast(obj)));
+ List<Handle<Script> > scripts;
+ {
+ HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
+ DisallowHeapAllocation no_allocation;
+ for (HeapObject* obj = iterator.next(); obj != NULL;
+ obj = iterator.next()) {
+ if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
+ scripts.Add(Handle<Script>(Script::cast(obj)));
+ }
}
}
+
+ GlobalHandles* global_handles = isolate_->global_handles();
+ table_ = Handle<WeakValueHashTable>::cast(global_handles->Create(
+ Object::cast(*WeakValueHashTable::New(isolate_, scripts.length()))));
+ for (int i = 0; i < scripts.length(); i++) Add(scripts[i]);
}
void ScriptCache::Add(Handle<Script> script) {
- GlobalHandles* global_handles = isolate_->global_handles();
- // Create an entry in the hash map for the script.
- int id = script->id()->value();
- HashMap::Entry* entry =
- HashMap::LookupOrInsert(reinterpret_cast<void*>(id), Hash(id));
- if (entry->value != NULL) {
+ HandleScope scope(isolate_);
+ Handle<Smi> id(script->id(), isolate_);
+
#ifdef DEBUG
- // The code deserializer may introduce duplicate Script objects.
- // Assert that the Script objects with the same id have the same name.
- Handle<Script> found(reinterpret_cast<Script**>(entry->value));
+ Handle<Object> lookup(table_->LookupWeak(id), isolate_);
+ if (!lookup->IsTheHole()) {
+ Handle<Script> found = Handle<Script>::cast(lookup);
DCHECK(script->id() == found->id());
DCHECK(!script->name()->IsString() ||
String::cast(script->name())->Equals(String::cast(found->name())));
-#endif
- return;
- }
- // Globalize the script object, make it weak and use the location of the
- // global handle as the value in the hash map.
- Handle<Script> script_ =
- Handle<Script>::cast(global_handles->Create(*script));
- GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
- this,
- ScriptCache::HandleWeakScript);
- entry->value = script_.location();
-}
-
-
-Handle<FixedArray> ScriptCache::GetScripts() {
- Factory* factory = isolate_->factory();
- Handle<FixedArray> instances = factory->NewFixedArray(occupancy());
- int count = 0;
- for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
- DCHECK(entry->value != NULL);
- if (entry->value != NULL) {
- instances->set(count, *reinterpret_cast<Script**>(entry->value));
- count++;
- }
}
- return instances;
-}
+#endif
+ Handle<WeakValueHashTable> new_table =
+ WeakValueHashTable::PutWeak(table_, id, script);
-void ScriptCache::Clear() {
- // Iterate the script cache to get rid of all the weak handles.
- for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
- DCHECK(entry != NULL);
- Object** location = reinterpret_cast<Object**>(entry->value);
- DCHECK((*location)->IsScript());
- GlobalHandles::ClearWeakness(location);
- GlobalHandles::Destroy(location);
- }
- // Clear the content of the hash map.
- HashMap::Clear();
+ if (new_table.is_identical_to(table_)) return;
+ GlobalHandles* global_handles = isolate_->global_handles();
+ global_handles->Destroy(Handle<Object>::cast(table_).location());
+ table_ = Handle<WeakValueHashTable>::cast(
+ global_handles->Create(Object::cast(*new_table)));
}
-void ScriptCache::HandleWeakScript(
- const v8::WeakCallbackData<v8::Value, void>& data) {
- // Retrieve the script identifier.
- Handle<Object> object = Utils::OpenHandle(*data.GetValue());
- int id = Handle<Script>::cast(object)->id()->value();
- void* key = reinterpret_cast<void*>(id);
- uint32_t hash = Hash(id);
-
- // Remove the corresponding entry from the cache.
- ScriptCache* script_cache =
- reinterpret_cast<ScriptCache*>(data.GetParameter());
- HashMap::Entry* entry = script_cache->Lookup(key, hash);
- DCHECK_NOT_NULL(entry);
- Object** location = reinterpret_cast<Object**>(entry->value);
- script_cache->Remove(key, hash);
-
- // Clear the weak handle.
- GlobalHandles::Destroy(location);
+ScriptCache::~ScriptCache() {
+ isolate_->global_handles()->Destroy(Handle<Object>::cast(table_).location());
+ table_ = Handle<WeakValueHashTable>();
}
@@ -645,15 +600,10 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
// Compile the script.
Handle<SharedFunctionInfo> function_info;
function_info = Compiler::CompileScript(
- source_code, script_name, 0, 0, false, false, Handle<Object>(), context,
- NULL, NULL, ScriptCompiler::kNoCompileOptions, NATIVES_CODE, false);
-
- // Silently ignore stack overflows during compilation.
- if (function_info.is_null()) {
- DCHECK(isolate->has_pending_exception());
- isolate->clear_pending_exception();
- return false;
- }
+ source_code, script_name, 0, 0, ScriptOriginOptions(), Handle<Object>(),
+ context, NULL, NULL, ScriptCompiler::kNoCompileOptions, NATIVES_CODE,
+ false);
+ if (function_info.is_null()) return false;
// Execute the shared function in the debugger context.
Handle<JSFunction> function =
@@ -668,16 +618,16 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
DCHECK(!isolate->has_pending_exception());
MessageLocation computed_location;
isolate->ComputeLocation(&computed_location);
- Handle<Object> message = MessageHandler::MakeMessageObject(
- isolate, "error_loading_debugger", &computed_location,
- Vector<Handle<Object> >::empty(), Handle<JSArray>());
+ Handle<JSMessageObject> message = MessageHandler::MakeMessageObject(
+ isolate, MessageTemplate::kDebuggerLoading, &computed_location,
+ isolate->factory()->undefined_value(), Handle<JSArray>());
DCHECK(!isolate->has_pending_exception());
Handle<Object> exception;
if (maybe_exception.ToHandle(&exception)) {
isolate->set_pending_exception(*exception);
MessageHandler::ReportMessage(isolate, NULL, message);
- isolate->clear_pending_exception();
}
+ DCHECK(!maybe_exception.is_null());
return false;
}
@@ -705,11 +655,9 @@ bool Debug::Load() {
// Create the debugger context.
HandleScope scope(isolate_);
ExtensionConfiguration no_extensions;
- Handle<Context> context =
- isolate_->bootstrapper()->CreateEnvironment(
- MaybeHandle<JSGlobalProxy>(),
- v8::Handle<ObjectTemplate>(),
- &no_extensions);
+ Handle<Context> context = isolate_->bootstrapper()->CreateEnvironment(
+ MaybeHandle<JSGlobalProxy>(), v8::Local<ObjectTemplate>(),
+ &no_extensions);
// Fail if no context could be created.
if (context.is_null()) return false;
@@ -1105,8 +1053,8 @@ void Debug::ClearAllBreakPoints() {
void Debug::FloodWithOneShot(Handle<JSFunction> function,
BreakLocatorType type) {
- // Do not ever break in native functions.
- if (function->IsFromNativeScript()) return;
+ // Do not ever break in native and extension functions.
+ if (!function->IsSubjectToDebugging()) return;
PrepareForBreakPoints();
@@ -1131,7 +1079,7 @@ void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) {
isolate_);
if (!bindee.is_null() && bindee->IsJSFunction() &&
- !JSFunction::cast(*bindee)->IsFromNativeScript()) {
+ JSFunction::cast(*bindee)->IsSubjectToDebugging()) {
Handle<JSFunction> bindee_function(JSFunction::cast(*bindee));
FloodWithOneShotGeneric(bindee_function);
}
@@ -1189,7 +1137,7 @@ void Debug::FloodHandlerWithOneShot() {
for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) {
JavaScriptFrame* frame = it.frame();
int stack_slots = 0; // The computed stack slot count is not used.
- if (frame->LookupExceptionHandlerInTable(&stack_slots) > 0) {
+ if (frame->LookupExceptionHandlerInTable(&stack_slots, NULL) > 0) {
// Flood the function with the catch/finally block with break points.
FloodWithOneShot(Handle<JSFunction>(frame->function()));
return;
@@ -1281,8 +1229,6 @@ void Debug::PrepareStep(StepAction step_action,
Handle<DebugInfo> debug_info = GetDebugInfo(shared);
// Compute whether or not the target is a call target.
- bool is_load_or_store = false;
- bool is_inline_cache_stub = false;
bool is_at_restarted_function = false;
Handle<Code> call_function_stub;
@@ -1295,8 +1241,6 @@ void Debug::PrepareStep(StepAction step_action,
if (thread_local_.restarter_frame_function_pointer_ == NULL) {
if (location.IsCodeTarget()) {
Handle<Code> target_code = location.CodeTarget();
- is_inline_cache_stub = target_code->is_inline_cache_stub();
- is_load_or_store = is_inline_cache_stub && !target_code->is_call_stub();
// Check if target code is CallFunction stub.
Handle<Code> maybe_call_function_stub = target_code;
@@ -1329,9 +1273,9 @@ void Debug::PrepareStep(StepAction step_action,
DCHECK(location.IsExit());
frames_it.Advance();
}
- // Skip builtin functions on the stack.
+ // Skip native and extension functions on the stack.
while (!frames_it.done() &&
- frames_it.frame()->function()->IsFromNativeScript()) {
+ !frames_it.frame()->function()->IsSubjectToDebugging()) {
frames_it.Advance();
}
// Step out: If there is a JavaScript caller frame, we need to
@@ -1343,21 +1287,10 @@ void Debug::PrepareStep(StepAction step_action,
// Set target frame pointer.
ActivateStepOut(frames_it.frame());
}
- } else if (!(is_inline_cache_stub || location.IsConstructCall() ||
- !call_function_stub.is_null() || is_at_restarted_function) ||
- step_action == StepNext || step_action == StepMin) {
- // Step next or step min.
-
- // Fill the current function with one-shot break points.
- // If we are stepping into another frame, only fill calls and returns.
- FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS
- : ALL_BREAK_LOCATIONS);
-
- // Remember source position and frame to handle step next.
- thread_local_.last_statement_position_ =
- debug_info->code()->SourceStatementPosition(summary.pc());
- thread_local_.last_fp_ = frame->UnpaddedFP();
- } else {
+ return;
+ }
+
+ if (step_action != StepNext && step_action != StepMin) {
// If there's restarter frame on top of the stack, just get the pointer
// to function which is going to be restarted.
if (is_at_restarted_function) {
@@ -1399,11 +1332,16 @@ void Debug::PrepareStep(StepAction step_action,
Isolate* isolate = JSFunction::cast(fun)->GetIsolate();
Code* apply = isolate->builtins()->builtin(Builtins::kFunctionApply);
Code* call = isolate->builtins()->builtin(Builtins::kFunctionCall);
+ // Find target function on the expression stack for expression like
+ // Function.call.call...apply(...)
+ int i = 1;
while (fun->IsJSFunction()) {
Code* code = JSFunction::cast(fun)->shared()->code();
if (code != apply && code != call) break;
- fun = frame->GetExpression(
- expressions_count - 1 - call_function_arg_count);
+ DCHECK(expressions_count - i - call_function_arg_count >= 0);
+ fun = frame->GetExpression(expressions_count - i -
+ call_function_arg_count);
+ i -= 1;
}
}
@@ -1413,36 +1351,21 @@ void Debug::PrepareStep(StepAction step_action,
}
}
- // Fill the current function with one-shot break points even for step in on
- // a call target as the function called might be a native function for
- // which step in will not stop. It also prepares for stepping in
- // getters/setters.
- // If we are stepping into another frame, only fill calls and returns.
- FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS
- : ALL_BREAK_LOCATIONS);
-
- if (is_load_or_store) {
- // Remember source position and frame to handle step in getter/setter. If
- // there is a custom getter/setter it will be handled in
- // Object::Get/SetPropertyWithAccessor, otherwise the step action will be
- // propagated on the next Debug::Break.
- thread_local_.last_statement_position_ =
- debug_info->code()->SourceStatementPosition(summary.pc());
- thread_local_.last_fp_ = frame->UnpaddedFP();
- }
-
- // Step in or Step in min
- // Step in through construct call requires no changes to the running code.
- // Step in through getters/setters should already be prepared as well
- // because caller of this function (Debug::PrepareStep) is expected to
- // flood the top frame's function with one shot breakpoints.
- // Step in through CallFunction stub should also be prepared by caller of
- // this function (Debug::PrepareStep) which should flood target function
- // with breakpoints.
- DCHECK(location.IsConstructCall() || is_inline_cache_stub ||
- !call_function_stub.is_null() || is_at_restarted_function);
- ActivateStepIn(frame);
+ ActivateStepIn(function, frame);
}
+
+ // Fill the current function with one-shot break points even for step in on
+ // a call target as the function called might be a native function for
+ // which step in will not stop. It also prepares for stepping in
+ // getters/setters.
+ // If we are stepping into another frame, only fill calls and returns.
+ FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS
+ : ALL_BREAK_LOCATIONS);
+
+ // Remember source position and frame to handle step next.
+ thread_local_.last_statement_position_ =
+ debug_info->code()->SourceStatementPosition(summary.pc());
+ thread_local_.last_fp_ = frame->UnpaddedFP();
}
@@ -1532,30 +1455,27 @@ Handle<Object> Debug::GetSourceBreakLocations(
// Handle stepping into a function.
-void Debug::HandleStepIn(Handle<Object> function_obj, Handle<Object> holder,
- Address fp, bool is_constructor) {
+void Debug::HandleStepIn(Handle<Object> function_obj, bool is_constructor) {
// Flood getter/setter if we either step in or step to another frame.
bool step_frame = thread_local_.last_step_action_ == StepFrame;
if (!StepInActive() && !step_frame) return;
if (!function_obj->IsJSFunction()) return;
Handle<JSFunction> function = Handle<JSFunction>::cast(function_obj);
Isolate* isolate = function->GetIsolate();
- // If the frame pointer is not supplied by the caller find it.
- if (fp == 0) {
- StackFrameIterator it(isolate);
+
+ StackFrameIterator it(isolate);
+ it.Advance();
+ // For constructor functions skip another frame.
+ if (is_constructor) {
+ DCHECK(it.frame()->is_construct());
it.Advance();
- // For constructor functions skip another frame.
- if (is_constructor) {
- DCHECK(it.frame()->is_construct());
- it.Advance();
- }
- fp = it.frame()->fp();
}
+ Address fp = it.frame()->fp();
// Flood the function with one-shot break points if it is called from where
// step into was requested, or when stepping into a new frame.
if (fp == thread_local_.step_into_fp_ || step_frame) {
- FloodWithOneShotGeneric(function, holder);
+ FloodWithOneShotGeneric(function, Handle<Object>());
}
}
@@ -1589,8 +1509,12 @@ void Debug::ClearOneShot() {
}
-void Debug::ActivateStepIn(StackFrame* frame) {
+void Debug::ActivateStepIn(Handle<JSFunction> function, StackFrame* frame) {
DCHECK(!StepOutActive());
+ // Make sure IC state is clean. This is so that we correct flood
+ // accessor pairs when stepping in.
+ function->code()->ClearInlineCaches();
+ function->shared()->feedback_vector()->ClearICSlots(function->shared());
thread_local_.step_into_fp_ = frame->UnpaddedFP();
}
@@ -1748,7 +1672,7 @@ static void RedirectActivationsToRecompiledCodeOnThread(
reinterpret_cast<intptr_t>(new_pc));
}
- if (FLAG_enable_ool_constant_pool) {
+ if (FLAG_enable_embedded_constant_pool) {
// Update constant pool pointer for new code.
frame->set_constant_pool(new_code->constant_pool());
}
@@ -1921,7 +1845,8 @@ void Debug::PrepareForBreakPoints() {
if (kind == Code::OPTIMIZED_FUNCTION) {
// Optimized code can only get here if DeoptimizeAll did not
// deoptimize turbo fan code.
- DCHECK(!FLAG_turbo_deoptimization);
+ DCHECK(!FLAG_turbo_asm_deoptimization);
+ DCHECK(function->shared()->asm_function());
DCHECK(function->code()->is_turbofanned());
function->ReplaceCode(fallback);
}
@@ -1981,10 +1906,12 @@ void Debug::PrepareForBreakPoints() {
for (int i = 0; i < active_functions.length(); i++) {
Handle<JSFunction> function = active_functions[i];
Handle<SharedFunctionInfo> shared(function->shared());
-
- // If recompilation is not possible just skip it.
- if (shared->is_toplevel()) continue;
- if (!shared->allows_lazy_compilation()) continue;
+ if (!shared->allows_lazy_compilation()) {
+ // Ignore functions that cannot be recompiled. Fortunately, those are
+ // only ones that are not subject to debugging in the first place.
+ DCHECK(!function->IsSubjectToDebugging());
+ continue;
+ }
if (shared->code()->kind() == Code::BUILTIN) continue;
EnsureFunctionHasDebugBreakSlots(function);
@@ -2000,126 +1927,126 @@ void Debug::PrepareForBreakPoints() {
}
+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) {
- // 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();
+ 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;
+ finder.NewCandidate(SharedFunctionInfo::cast(item));
+ }
+ 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* candidate_closure = NULL;
+ SharedFunctionInfo* candidate = NULL;
+ if (object->IsJSFunction()) {
+ candidate_closure = JSFunction::cast(object);
+ candidate = candidate_closure->shared();
+ } else if (object->IsSharedFunctionInfo()) {
+ candidate = SharedFunctionInfo::cast(object);
+ if (!candidate->allows_lazy_compilation_without_context()) continue;
+ } else {
+ continue;
}
- 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;
- }
- }
- }
+ if (candidate->script() == *script) {
+ finder.NewCandidate(candidate, candidate_closure);
}
- } // 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::BuildFunctionInfo 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();
+ }
+ closure = finder.ResultClosure();
+ shared = finder.Result();
}
- } // 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 (closure == NULL ? !CompileToRevealInnerFunctions(shared)
+ : !CompileToRevealInnerFunctions(closure)) {
+ break;
}
}
-
- return target;
+ return isolate_->factory()->undefined_value();
}
@@ -2143,10 +2070,6 @@ bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
return false;
}
- // Make sure IC state is clean.
- shared->code()->ClearInlineCaches();
- shared->feedback_vector()->ClearICSlots(*shared);
-
// Create the debug info object.
Handle<DebugInfo> debug_info = isolate->factory()->NewDebugInfo(shared);
@@ -2507,7 +2430,7 @@ void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) {
HandleScope scope(isolate_);
// Check whether the promise has been marked as having triggered a message.
Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
- if (JSObject::GetDataProperty(promise, key)->IsUndefined()) {
+ if (JSReceiver::GetDataProperty(promise, key)->IsUndefined()) {
OnException(value, promise);
}
}
@@ -2516,14 +2439,15 @@ void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) {
MaybeHandle<Object> Debug::PromiseHasUserDefinedRejectHandler(
Handle<JSObject> promise) {
Handle<JSFunction> fun = Handle<JSFunction>::cast(
- JSObject::GetDataProperty(isolate_->js_builtins_object(),
- isolate_->factory()->NewStringFromStaticChars(
- "$promiseHasUserDefinedRejectHandler")));
+ JSReceiver::GetDataProperty(isolate_->js_builtins_object(),
+ isolate_->factory()->NewStringFromStaticChars(
+ "$promiseHasUserDefinedRejectHandler")));
return Execution::Call(isolate_, fun, promise, 0, NULL);
}
void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
+ // In our prediction, try-finally is not considered to catch.
Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher();
bool uncaught = (catch_type == Isolate::NOT_CAUGHT);
if (promise->IsJSObject()) {
@@ -2803,6 +2727,7 @@ void Debug::ProcessCompileEventInDebugScope(v8::DebugEvent event,
Handle<Context> Debug::GetDebugContext() {
+ if (!is_loaded()) return Handle<Context>();
DebugScope debug_scope(this);
if (debug_scope.failed()) return Handle<Context>();
// The global handle may be destroyed soon after. Return it reboxed.
@@ -2977,16 +2902,17 @@ void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
void Debug::UpdateState() {
- is_active_ = message_handler_ != NULL || !event_listener_.is_null();
- if (is_active_ || in_debug_scope()) {
+ bool is_active = message_handler_ != NULL || !event_listener_.is_null();
+ if (is_active || in_debug_scope()) {
// Note that the debug context could have already been loaded to
// bootstrap test cases.
isolate_->compilation_cache()->Disable();
- is_active_ = Load();
+ is_active = Load();
} else if (is_loaded()) {
isolate_->compilation_cache()->Enable();
Unload();
}
+ is_active_ = is_active;
}
@@ -3211,7 +3137,7 @@ bool MessageImpl::WillStartRunning() const {
}
-v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
+v8::Local<v8::Object> MessageImpl::GetExecutionState() const {
return v8::Utils::ToLocal(exec_state_);
}
@@ -3221,12 +3147,12 @@ v8::Isolate* MessageImpl::GetIsolate() const {
}
-v8::Handle<v8::Object> MessageImpl::GetEventData() const {
+v8::Local<v8::Object> MessageImpl::GetEventData() const {
return v8::Utils::ToLocal(event_data_);
}
-v8::Handle<v8::String> MessageImpl::GetJSON() const {
+v8::Local<v8::String> MessageImpl::GetJSON() const {
Isolate* isolate = event_data_->GetIsolate();
v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
@@ -3235,14 +3161,14 @@ v8::Handle<v8::String> MessageImpl::GetJSON() const {
Handle<Object> fun = Object::GetProperty(
isolate, event_data_, "toJSONProtocol").ToHandleChecked();
if (!fun->IsJSFunction()) {
- return v8::Handle<v8::String>();
+ return v8::Local<v8::String>();
}
MaybeHandle<Object> maybe_json =
Execution::TryCall(Handle<JSFunction>::cast(fun), event_data_, 0, NULL);
Handle<Object> json;
if (!maybe_json.ToHandle(&json) || !json->IsString()) {
- return v8::Handle<v8::String>();
+ return v8::Local<v8::String>();
}
return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
} else {
@@ -3251,9 +3177,9 @@ v8::Handle<v8::String> MessageImpl::GetJSON() const {
}
-v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
+v8::Local<v8::Context> MessageImpl::GetEventContext() const {
Isolate* isolate = event_data_->GetIsolate();
- v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
+ v8::Local<v8::Context> context = GetDebugEventContext(isolate);
// Isolate::context() may be NULL when "script collected" event occurs.
DCHECK(!context.IsEmpty());
return context;
@@ -3282,22 +3208,22 @@ DebugEvent EventDetailsImpl::GetEvent() const {
}
-v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
+v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const {
return v8::Utils::ToLocal(exec_state_);
}
-v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
+v8::Local<v8::Object> EventDetailsImpl::GetEventData() const {
return v8::Utils::ToLocal(event_data_);
}
-v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
+v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const {
return GetDebugEventContext(exec_state_->GetIsolate());
}
-v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
+v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const {
return v8::Utils::ToLocal(callback_data_);
}
@@ -3405,4 +3331,5 @@ void LockingCommandMessageQueue::Clear() {
queue_.Clear();
}
-} } // namespace v8::internal
+} // namespace internal
+} // namespace v8