live_edit_enabled_(true), // TODO(yangguo): set to false by default.
has_break_points_(false),
break_disabled_(false),
+ in_debug_event_listener_(false),
break_on_exception_(false),
break_on_uncaught_exception_(false),
script_cache_(NULL),
thread_local_.step_into_fp_ = 0;
thread_local_.step_out_fp_ = 0;
// TODO(isolates): frames_are_dropped_?
- thread_local_.current_debug_scope_ = NULL;
+ base::NoBarrier_Store(&thread_local_.current_debug_scope_,
+ static_cast<base::AtomicWord>(NULL));
thread_local_.restarter_frame_function_pointer_ = NULL;
}
Heap* heap = isolate_->heap();
HandleScope scope(isolate_);
- // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
- // rid of all the cached script wrappers and the second gets rid of the
- // scripts which are no longer referenced.
- heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptCache");
+ // Perform a GC to get rid of all unreferenced scripts.
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptCache");
// Scan heap for Script objects.
Debug* debug = reinterpret_cast<Isolate*>(data.GetIsolate())->debug();
DebugInfoListNode* node =
reinterpret_cast<DebugInfoListNode*>(data.GetParameter());
- // We need to clear all breakpoints associated with the function to restore
- // 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
- // Debug::FindSharedFunctionInfoInScript.
- BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
- it.ClearAllDebugBreak();
- debug->RemoveDebugInfo(node->debug_info());
+ debug->RemoveDebugInfo(node->debug_info().location());
#ifdef DEBUG
for (DebugInfoListNode* n = debug->debug_info_list_;
n != NULL;
GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles();
debug_info_ = Handle<DebugInfo>::cast(global_handles->Create(debug_info));
GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
- this,
- Debug::HandleWeakDebugInfo);
+ this, Debug::HandleWeakDebugInfo,
+ GlobalHandles::Phantom);
}
LiveEdit::InitializeThreadLocal(this);
// Just continue if breaks are disabled or debugger cannot be loaded.
- if (break_disabled_) return;
+ if (break_disabled()) return;
// Enter the debugger.
DebugScope debug_scope(this);
it.FindBreakLocationFromPosition(*source_position, STATEMENT_ALIGNED);
it.SetBreakPoint(break_point_object);
- *source_position = it.position();
+ *source_position = it.statement_position();
// At least one active break point now.
return debug_info->GetBreakPointCount() > 0;
it.FindBreakLocationFromPosition(position, alignment);
it.SetBreakPoint(break_point_object);
- *source_position = it.position() + shared->start_position();
+ position = (alignment == STATEMENT_ALIGNED) ? it.statement_position()
+ : it.position();
+
+ *source_position = position + shared->start_position();
// At least one active break point now.
DCHECK(debug_info->GetBreakPointCount() > 0);
// If there are no more break points left remove the debug info for this
// function.
if (debug_info->GetBreakPointCount() == 0) {
- RemoveDebugInfo(debug_info);
+ RemoveDebugInfoAndClearFromShared(debug_info);
}
return;
// Remove all debug info.
while (debug_info_list_ != NULL) {
- RemoveDebugInfo(debug_info_list_->debug_info());
+ RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
}
}
}
-bool Debug::PromiseHasRejectHandler(Handle<JSObject> promise) {
- Handle<JSFunction> fun = Handle<JSFunction>::cast(
- JSObject::GetDataProperty(isolate_->js_builtins_object(),
- isolate_->factory()->NewStringFromStaticChars(
- "PromiseHasRejectHandler")));
- Handle<Object> result =
- Execution::Call(isolate_, fun, promise, 0, NULL).ToHandleChecked();
- return result->IsTrue();
-}
-
-
void Debug::PrepareStep(StepAction step_action,
int step_count,
StackFrame::Id frame_id) {
BreakPointInfo* break_point_info =
BreakPointInfo::cast(debug_info->break_points()->get(i));
if (break_point_info->GetBreakPointCount() > 0) {
- Smi* position;
+ Smi* position = NULL;
switch (position_alignment) {
- case STATEMENT_ALIGNED:
- position = break_point_info->statement_position();
- break;
- case BREAK_POSITION_ALIGNED:
- position = break_point_info->source_position();
- break;
- default:
- UNREACHABLE();
- position = break_point_info->statement_position();
+ case STATEMENT_ALIGNED:
+ position = break_point_info->statement_position();
+ break;
+ case BREAK_POSITION_ALIGNED:
+ position = break_point_info->source_position();
+ break;
}
locations->set(count++, position);
}
+static bool SkipSharedFunctionInfo(SharedFunctionInfo* shared,
+ Object* active_code_marker) {
+ if (!shared->allows_lazy_compilation()) return true;
+ if (!shared->script()->IsScript()) return true;
+ Object* script = shared->script();
+ if (!script->IsScript()) return true;
+ if (Script::cast(script)->type()->value() == Script::TYPE_NATIVE) return true;
+ Code* shared_code = shared->code();
+ return shared_code->gc_metadata() == active_code_marker;
+}
+
+
+static inline bool HasDebugBreakSlots(Code* code) {
+ return code->kind() == Code::FUNCTION && code->has_debug_break_slots();
+}
+
+
void Debug::PrepareForBreakPoints() {
// If preparing for the first break point make sure to deoptimize all
// functions as debugging does not work with optimized code.
if (obj->IsJSFunction()) {
JSFunction* function = JSFunction::cast(obj);
SharedFunctionInfo* shared = function->shared();
-
- if (!shared->allows_lazy_compilation()) continue;
- if (!shared->script()->IsScript()) continue;
- if (function->IsFromNativeScript()) continue;
- if (shared->code()->gc_metadata() == active_code_marker) continue;
-
+ if (SkipSharedFunctionInfo(shared, active_code_marker)) continue;
if (shared->is_generator()) {
generator_functions.Add(Handle<JSFunction>(function, isolate_));
continue;
}
-
+ if (HasDebugBreakSlots(function->code())) continue;
+ Code* fallback = HasDebugBreakSlots(shared->code()) ? shared->code()
+ : *lazy_compile;
Code::Kind kind = function->code()->kind();
- if (kind == Code::FUNCTION &&
- !function->code()->has_debug_break_slots()) {
- function->ReplaceCode(*lazy_compile);
- function->shared()->ReplaceCode(*lazy_compile);
- } else if (kind == Code::BUILTIN &&
- (function->IsInOptimizationQueue() ||
- function->IsMarkedForOptimization() ||
- function->IsMarkedForConcurrentOptimization())) {
- // Abort in-flight compilation.
- Code* shared_code = function->shared()->code();
- if (shared_code->kind() == Code::FUNCTION &&
- shared_code->has_debug_break_slots()) {
- function->ReplaceCode(shared_code);
- } else {
- function->ReplaceCode(*lazy_compile);
- function->shared()->ReplaceCode(*lazy_compile);
- }
+ if (kind == Code::FUNCTION ||
+ (kind == Code::BUILTIN && // Abort in-flight compilation.
+ (function->IsInOptimizationQueue() ||
+ function->IsMarkedForOptimization() ||
+ function->IsMarkedForConcurrentOptimization()))) {
+ function->ReplaceCode(fallback);
+ }
+ if (kind == Code::OPTIMIZED_FUNCTION) {
+ // Optimized code can only get here if DeoptimizeAll did not
+ // deoptimize turbo fan code.
+ DCHECK(!FLAG_turbo_deoptimization);
+ DCHECK(function->code()->is_turbofanned());
+ function->ReplaceCode(fallback);
}
} else if (obj->IsJSGeneratorObject()) {
JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
gen->set_continuation(code_offset);
suspended_generators.Add(Handle<JSGeneratorObject>(gen, isolate_));
+ } else if (obj->IsSharedFunctionInfo()) {
+ SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
+ if (SkipSharedFunctionInfo(shared, active_code_marker)) continue;
+ if (shared->is_generator()) continue;
+ if (HasDebugBreakSlots(shared->code())) continue;
+ shared->ReplaceCode(*lazy_compile);
}
}
}
-void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
+// This uses the location of a handle to look up the debug info in the debug
+// info list, but it doesn't use the actual debug info for anything. Therefore
+// if the debug info has been collected by the GC, we can be sure that this
+// method will not attempt to resurrect it.
+void Debug::RemoveDebugInfo(DebugInfo** debug_info) {
DCHECK(debug_info_list_ != NULL);
// Run through the debug info objects to find this one and remove it.
DebugInfoListNode* prev = NULL;
DebugInfoListNode* current = debug_info_list_;
while (current != NULL) {
- if (*current->debug_info() == *debug_info) {
+ if (current->debug_info().location() == debug_info) {
// Unlink from list. If prev is NULL we are looking at the first element.
if (prev == NULL) {
debug_info_list_ = current->next();
} else {
prev->set_next(current->next());
}
- current->debug_info()->shared()->set_debug_info(
- isolate_->heap()->undefined_value());
delete current;
// If there are no more debug info objects there are not more break
}
+void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
+ HandleScope scope(isolate_);
+ Handle<SharedFunctionInfo> shared(debug_info->shared());
+
+ RemoveDebugInfo(debug_info.location());
+
+ shared->set_debug_info(isolate_->heap()->undefined_value());
+}
+
+
void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
after_break_target_ = NULL;
HandleScope scope(isolate_);
// If there are no break points this cannot be break at return, as
- // the debugger statement and stack guard bebug break cannot be at
+ // the debugger statement and stack guard debug break cannot be at
// return.
if (!has_break_points_) {
return false;
void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) {
if (in_debug_scope() || ignore_events()) return;
HandleScope scope(isolate_);
- OnException(value, false, promise);
+ // 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()) {
+ OnException(value, false, promise);
+ }
+}
+
+
+MaybeHandle<Object> Debug::PromiseHasUserDefinedRejectHandler(
+ Handle<JSObject> promise) {
+ Handle<JSFunction> fun = Handle<JSFunction>::cast(
+ JSObject::GetDataProperty(isolate_->js_builtins_object(),
+ isolate_->factory()->NewStringFromStaticChars(
+ "PromiseHasUserDefinedRejectHandler")));
+ return Execution::Call(isolate_, fun, promise, 0, NULL);
}
void Debug::OnException(Handle<Object> exception, bool uncaught,
Handle<Object> promise) {
- if (promise->IsJSObject()) {
- uncaught |= !PromiseHasRejectHandler(Handle<JSObject>::cast(promise));
+ if (!uncaught && promise->IsJSObject()) {
+ Handle<JSObject> jspromise = Handle<JSObject>::cast(promise);
+ // Mark the promise as already having triggered a message.
+ Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
+ JSObject::SetProperty(jspromise, key, key, STRICT).Assert();
+ // Check whether the promise reject is considered an uncaught exception.
+ Handle<Object> has_reject_handler;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate_, has_reject_handler,
+ PromiseHasUserDefinedRejectHandler(jspromise), /* void */);
+ uncaught = has_reject_handler->IsFalse();
}
// Bail out if exception breaks are not active
if (uncaught) {
Handle<Object> exec_state,
Handle<Object> event_data,
v8::Debug::ClientData* client_data) {
+ bool previous = in_debug_event_listener_;
+ in_debug_event_listener_ = true;
if (event_listener_->IsForeign()) {
// Invoke the C debug event listener.
v8::Debug::EventCallback callback =
Execution::TryCall(Handle<JSFunction>::cast(event_listener_),
global, arraysize(argv), argv);
}
+ in_debug_event_listener_ = previous;
}
// Ignore debug break during bootstrapping.
if (isolate_->bootstrapper()->IsActive()) return;
// Just continue if breaks are disabled.
- if (break_disabled_) return;
+ if (break_disabled()) return;
// Ignore debug break if debugger is not active.
if (!is_active()) return;
no_termination_exceptons_(debug_->isolate_,
StackGuard::TERMINATE_EXECUTION) {
// Link recursive debugger entry.
- debug_->thread_local_.current_debug_scope_ = this;
+ base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
+ reinterpret_cast<base::AtomicWord>(this));
// Store the previous break id and frame id.
break_id_ = debug_->break_id();
}
// Leaving this debugger entry.
- debug_->thread_local_.current_debug_scope_ = prev_;
+ base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
+ reinterpret_cast<base::AtomicWord>(prev_));
// Restore to the previous break state.
debug_->thread_local_.break_frame_id_ = break_frame_id_;
v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
Isolate* isolate = event_data_->GetIsolate();
v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
- // Isolate::context() may be NULL when "script collected" event occures.
+ // Isolate::context() may be NULL when "script collected" event occurs.
DCHECK(!context.IsEmpty());
return context;
}