summaryrefslogtreecommitdiff
path: root/deps/v8/src/debug.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/debug.cc')
-rw-r--r--deps/v8/src/debug.cc650
1 files changed, 343 insertions, 307 deletions
diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc
index d7667f19c8..3ecf8bada7 100644
--- a/deps/v8/src/debug.cc
+++ b/deps/v8/src/debug.cc
@@ -1,29 +1,6 @@
// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#include "v8.h"
@@ -53,9 +30,6 @@
namespace v8 {
namespace internal {
-#ifdef ENABLE_DEBUGGER_SUPPORT
-
-
Debug::Debug(Isolate* isolate)
: has_break_points_(false),
script_cache_(NULL),
@@ -63,10 +37,11 @@ Debug::Debug(Isolate* isolate)
disable_break_(false),
break_on_exception_(false),
break_on_uncaught_exception_(false),
- debug_break_return_(NULL),
- debug_break_slot_(NULL),
+ promise_catch_handlers_(0),
+ promise_getters_(0),
isolate_(isolate) {
memset(registers_, 0, sizeof(JSCallerSavedBuffer));
+ ThreadInit();
}
@@ -406,6 +381,7 @@ bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) {
if (target_code->kind() == Code::STUB) {
return target_code->major_key() == CodeStub::CallFunction;
}
+ return target_code->is_call_stub();
}
return false;
}
@@ -688,21 +664,6 @@ void ScriptCache::HandleWeakScript(
}
-void Debug::SetUp(bool create_heap_objects) {
- ThreadInit();
- if (create_heap_objects) {
- // Get code to handle debug break on return.
- debug_break_return_ =
- isolate_->builtins()->builtin(Builtins::kReturn_DebugBreak);
- ASSERT(debug_break_return_->IsCode());
- // Get code to handle debug break in debug break slots.
- debug_break_slot_ =
- isolate_->builtins()->builtin(Builtins::kSlot_DebugBreak);
- ASSERT(debug_break_slot_->IsCode());
- }
-}
-
-
void Debug::HandleWeakDebugInfo(
const v8::WeakCallbackData<v8::Value, void>& data) {
Debug* debug = reinterpret_cast<Isolate*>(data.GetIsolate())->debug();
@@ -753,8 +714,8 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
Handle<String> source_code =
isolate->bootstrapper()->NativesSourceLookup(index);
Vector<const char> name = Natives::GetScriptName(index);
- Handle<String> script_name = factory->NewStringFromAscii(name);
- ASSERT(!script_name.is_null());
+ Handle<String> script_name =
+ factory->NewStringFromAscii(name).ToHandleChecked();
Handle<Context> context = isolate->native_context();
// Compile the script.
@@ -774,19 +735,19 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
}
// Execute the shared function in the debugger context.
- bool caught_exception;
Handle<JSFunction> function =
factory->NewFunctionFromSharedFunctionInfo(function_info, context);
- Handle<Object> exception =
+ Handle<Object> exception;
+ MaybeHandle<Object> result =
Execution::TryCall(function,
Handle<Object>(context->global_object(), isolate),
0,
NULL,
- &caught_exception);
+ &exception);
// Check for caught exceptions.
- if (caught_exception) {
+ if (result.is_null()) {
ASSERT(!isolate->has_pending_exception());
MessageLocation computed_location;
isolate->ComputeLocation(&computed_location);
@@ -847,7 +808,7 @@ bool Debug::Load() {
Handle<String> key = isolate_->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("builtins"));
Handle<GlobalObject> global = Handle<GlobalObject>(context->global_object());
- RETURN_IF_EMPTY_HANDLE_VALUE(
+ RETURN_ON_EXCEPTION_VALUE(
isolate_,
JSReceiver::SetProperty(global,
key,
@@ -906,12 +867,6 @@ void Debug::PreemptionWhileInDebugger() {
}
-void Debug::Iterate(ObjectVisitor* v) {
- v->VisitPointer(BitCast<Object**>(&(debug_break_return_)));
- v->VisitPointer(BitCast<Object**>(&(debug_break_slot_)));
-}
-
-
Object* Debug::Break(Arguments args) {
Heap* heap = isolate_->heap();
HandleScope scope(isolate_);
@@ -1061,7 +1016,7 @@ Object* Debug::Break(Arguments args) {
}
-RUNTIME_FUNCTION(Object*, Debug_Break) {
+RUNTIME_FUNCTION(Debug_Break) {
return isolate->debug()->Break(args);
}
@@ -1116,31 +1071,26 @@ bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
Handle<String> is_break_point_triggered_string =
factory->InternalizeOneByteString(
STATIC_ASCII_VECTOR("IsBreakPointTriggered"));
+ Handle<GlobalObject> debug_global(debug_context()->global_object());
Handle<JSFunction> check_break_point =
- Handle<JSFunction>(JSFunction::cast(
- debug_context()->global_object()->GetPropertyNoExceptionThrown(
- *is_break_point_triggered_string)));
+ Handle<JSFunction>::cast(Object::GetProperty(
+ debug_global, is_break_point_triggered_string).ToHandleChecked());
// Get the break id as an object.
Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
// Call HandleBreakPointx.
- bool caught_exception;
Handle<Object> argv[] = { break_id, break_point_object };
- Handle<Object> result = Execution::TryCall(check_break_point,
- isolate_->js_builtins_object(),
- ARRAY_SIZE(argv),
- argv,
- &caught_exception);
-
- // If exception or non boolean result handle as not triggered
- if (caught_exception || !result->IsBoolean()) {
+ Handle<Object> result;
+ if (!Execution::TryCall(check_break_point,
+ isolate_->js_builtins_object(),
+ ARRAY_SIZE(argv),
+ argv).ToHandle(&result)) {
return false;
}
// Return whether the break point is triggered.
- ASSERT(!result.is_null());
- return (*result)->IsTrue();
+ return result->IsTrue();
}
@@ -1348,6 +1298,53 @@ bool Debug::IsBreakOnException(ExceptionBreakType type) {
}
+void Debug::PromiseHandlePrologue(Handle<JSFunction> promise_getter) {
+ Handle<JSFunction> promise_getter_global = Handle<JSFunction>::cast(
+ isolate_->global_handles()->Create(*promise_getter));
+ StackHandler* handler =
+ StackHandler::FromAddress(Isolate::handler(isolate_->thread_local_top()));
+ promise_getters_.Add(promise_getter_global);
+ promise_catch_handlers_.Add(handler);
+}
+
+
+void Debug::PromiseHandleEpilogue() {
+ if (promise_catch_handlers_.length() == 0) return;
+ promise_catch_handlers_.RemoveLast();
+ Handle<Object> promise_getter = promise_getters_.RemoveLast();
+ isolate_->global_handles()->Destroy(promise_getter.location());
+}
+
+
+Handle<Object> Debug::GetPromiseForUncaughtException() {
+ Handle<Object> undefined = isolate_->factory()->undefined_value();
+ if (promise_getters_.length() == 0) return undefined;
+ Handle<JSFunction> promise_getter = promise_getters_.last();
+ StackHandler* promise_catch = promise_catch_handlers_.last();
+ // Find the top-most try-catch handler.
+ StackHandler* handler = StackHandler::FromAddress(
+ Isolate::handler(isolate_->thread_local_top()));
+ while (handler != NULL && !handler->is_catch()) {
+ handler = handler->next();
+ }
+#ifdef DEBUG
+ // Make sure that our promise catch handler is in the list of handlers,
+ // even if it's not the top-most try-catch handler.
+ StackHandler* temp = handler;
+ while (temp != promise_catch && !temp->is_catch()) {
+ temp = temp->next();
+ CHECK(temp != NULL);
+ }
+#endif // DEBUG
+
+ if (handler == promise_catch) {
+ return Execution::Call(
+ isolate_, promise_getter, undefined, 0, NULL).ToHandleChecked();
+ }
+ return undefined;
+}
+
+
void Debug::PrepareStep(StepAction step_action,
int step_count,
StackFrame::Id frame_id) {
@@ -1425,6 +1422,9 @@ void Debug::PrepareStep(StepAction step_action,
bool is_call_target = false;
Address target = it.rinfo()->target_address();
Code* code = Code::GetCodeFromTargetAddress(target);
+ if (code->is_call_stub()) {
+ is_call_target = true;
+ }
if (code->is_inline_cache_stub()) {
is_inline_cache_stub = true;
is_load_or_store = !is_call_target;
@@ -1439,8 +1439,9 @@ void Debug::PrepareStep(StepAction step_action,
maybe_call_function_stub =
Code::GetCodeFromTargetAddress(original_target);
}
- if (maybe_call_function_stub->kind() == Code::STUB &&
- maybe_call_function_stub->major_key() == CodeStub::CallFunction) {
+ if ((maybe_call_function_stub->kind() == Code::STUB &&
+ maybe_call_function_stub->major_key() == CodeStub::CallFunction) ||
+ maybe_call_function_stub->kind() == Code::CALL_IC) {
// Save reference to the code as we may need it to find out arguments
// count for 'step in' later.
call_function_stub = Handle<Code>(maybe_call_function_stub);
@@ -1496,6 +1497,7 @@ void Debug::PrepareStep(StepAction step_action,
} else if (!call_function_stub.is_null()) {
// If it's CallFunction stub ensure target function is compiled and flood
// it with one shot breakpoints.
+ bool is_call_ic = call_function_stub->kind() == Code::CALL_IC;
// Find out number of arguments from the stub minor key.
// Reverse lookup required as the minor key cannot be retrieved
@@ -1511,11 +1513,13 @@ void Debug::PrepareStep(StepAction step_action,
uint32_t key = Smi::cast(*obj)->value();
// Argc in the stub is the number of arguments passed - not the
// expected arguments of the called function.
- int call_function_arg_count =
- CallFunctionStub::ExtractArgcFromMinorKey(
+ int call_function_arg_count = is_call_ic
+ ? CallICStub::ExtractArgcFromMinorKey(CodeStub::MinorKeyFromKey(key))
+ : CallFunctionStub::ExtractArgcFromMinorKey(
CodeStub::MinorKeyFromKey(key));
- ASSERT(call_function_stub->major_key() ==
- CodeStub::MajorKeyFromKey(key));
+
+ ASSERT(is_call_ic ||
+ call_function_stub->major_key() == CodeStub::MajorKeyFromKey(key));
// Find target function on the expression stack.
// Expression stack looks like this (top to bottom):
@@ -1643,6 +1647,9 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
// 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();
@@ -1671,11 +1678,7 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
}
if (code->kind() == Code::STUB) {
ASSERT(code->major_key() == CodeStub::CallFunction);
- if (code->has_function_cache()) {
- return isolate->builtins()->CallFunctionStub_Recording_DebugBreak();
- } else {
- return isolate->builtins()->CallFunctionStub_DebugBreak();
- }
+ return isolate->builtins()->CallFunctionStub_DebugBreak();
}
UNREACHABLE();
@@ -1878,6 +1881,59 @@ static void CollectActiveFunctionsFromThread(
}
+// Figure out how many bytes of "pc_offset" correspond to actual code by
+// subtracting off the bytes that correspond to constant/veneer pools. See
+// Assembler::CheckConstPool() and Assembler::CheckVeneerPool(). Note that this
+// is only useful for architectures using constant pools or veneer pools.
+static int ComputeCodeOffsetFromPcOffset(Code *code, int pc_offset) {
+ ASSERT_EQ(code->kind(), Code::FUNCTION);
+ ASSERT(!code->has_debug_break_slots());
+ ASSERT_LE(0, pc_offset);
+ ASSERT_LT(pc_offset, code->instruction_end() - code->instruction_start());
+
+ int mask = RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
+ RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
+ byte *pc = code->instruction_start() + pc_offset;
+ int code_offset = pc_offset;
+ for (RelocIterator it(code, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ if (info->pc() >= pc) break;
+ ASSERT(RelocInfo::IsConstPool(info->rmode()));
+ code_offset -= static_cast<int>(info->data());
+ ASSERT_LE(0, code_offset);
+ }
+
+ return code_offset;
+}
+
+
+// The inverse of ComputeCodeOffsetFromPcOffset.
+static int ComputePcOffsetFromCodeOffset(Code *code, int code_offset) {
+ ASSERT_EQ(code->kind(), Code::FUNCTION);
+
+ int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
+ RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
+ RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
+ int reloc = 0;
+ for (RelocIterator it(code, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ if (info->pc() - code->instruction_start() - reloc >= code_offset) break;
+ if (RelocInfo::IsDebugBreakSlot(info->rmode())) {
+ reloc += Assembler::kDebugBreakSlotLength;
+ } else {
+ ASSERT(RelocInfo::IsConstPool(info->rmode()));
+ reloc += static_cast<int>(info->data());
+ }
+ }
+
+ int pc_offset = code_offset + reloc;
+
+ ASSERT_LT(code->instruction_start() + pc_offset, code->instruction_end());
+
+ return pc_offset;
+}
+
+
static void RedirectActivationsToRecompiledCodeOnThread(
Isolate* isolate,
ThreadLocalTop* top) {
@@ -1899,51 +1955,13 @@ static void RedirectActivationsToRecompiledCodeOnThread(
continue;
}
- // Iterate over the RelocInfo in the original code to compute the sum of the
- // constant pools and veneer pools sizes. (See Assembler::CheckConstPool()
- // and Assembler::CheckVeneerPool())
- // Note that this is only useful for architectures using constant pools or
- // veneer pools.
- int pool_mask = RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
- RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
- int frame_pool_size = 0;
- for (RelocIterator it(*frame_code, pool_mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- if (info->pc() >= frame->pc()) break;
- frame_pool_size += static_cast<int>(info->data());
- }
- intptr_t frame_offset =
- frame->pc() - frame_code->instruction_start() - frame_pool_size;
-
- // Iterate over the RelocInfo for new code to find the number of bytes
- // generated for debug slots and constant pools.
- int debug_break_slot_bytes = 0;
- int new_code_pool_size = 0;
- int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
- RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
- RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
- for (RelocIterator it(*new_code, mask); !it.done(); it.next()) {
- // Check if the pc in the new code with debug break
- // slots is before this slot.
- RelocInfo* info = it.rinfo();
- intptr_t new_offset = info->pc() - new_code->instruction_start() -
- new_code_pool_size - debug_break_slot_bytes;
- if (new_offset >= frame_offset) {
- break;
- }
-
- if (RelocInfo::IsDebugBreakSlot(info->rmode())) {
- debug_break_slot_bytes += Assembler::kDebugBreakSlotLength;
- } else {
- ASSERT(RelocInfo::IsConstPool(info->rmode()));
- // The size of the pools is encoded in the data.
- new_code_pool_size += static_cast<int>(info->data());
- }
- }
+ int old_pc_offset =
+ static_cast<int>(frame->pc() - frame_code->instruction_start());
+ int code_offset = ComputeCodeOffsetFromPcOffset(*frame_code, old_pc_offset);
+ int new_pc_offset = ComputePcOffsetFromCodeOffset(*new_code, code_offset);
// Compute the equivalent pc in the new code.
- byte* new_pc = new_code->instruction_start() + frame_offset +
- debug_break_slot_bytes + new_code_pool_size;
+ byte* new_pc = new_code->instruction_start() + new_pc_offset;
if (FLAG_trace_deopt) {
PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
@@ -1999,6 +2017,55 @@ class ActiveFunctionsRedirector : public ThreadVisitor {
};
+class ForceDebuggerActive {
+ public:
+ explicit ForceDebuggerActive(Isolate *isolate) {
+ isolate_ = isolate;
+ old_state_ = isolate->debugger()->force_debugger_active();
+ isolate_->debugger()->set_force_debugger_active(true);
+ }
+
+ ~ForceDebuggerActive() {
+ isolate_->debugger()->set_force_debugger_active(old_state_);
+ }
+
+ private:
+ Isolate *isolate_;
+ bool old_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForceDebuggerActive);
+};
+
+
+void Debug::MaybeRecompileFunctionForDebugging(Handle<JSFunction> function) {
+ ASSERT_EQ(Code::FUNCTION, function->code()->kind());
+ ASSERT_EQ(function->code(), function->shared()->code());
+
+ if (function->code()->has_debug_break_slots()) return;
+
+ ForceDebuggerActive force_debugger_active(isolate_);
+ MaybeHandle<Code> code = Compiler::GetCodeForDebugging(function);
+ // Recompilation can fail. In that case leave the code as it was.
+ if (!code.is_null())
+ function->ReplaceCode(*code.ToHandleChecked());
+ ASSERT_EQ(function->code(), function->shared()->code());
+}
+
+
+void Debug::RecompileAndRelocateSuspendedGenerators(
+ const List<Handle<JSGeneratorObject> > &generators) {
+ for (int i = 0; i < generators.length(); i++) {
+ Handle<JSFunction> fun(generators[i]->function());
+
+ MaybeRecompileFunctionForDebugging(fun);
+
+ int code_offset = generators[i]->continuation();
+ int pc_offset = ComputePcOffsetFromCodeOffset(fun->code(), code_offset);
+ generators[i]->set_continuation(pc_offset);
+ }
+}
+
+
void Debug::PrepareForBreakPoints() {
// If preparing for the first break point make sure to deoptimize all
// functions as debugging does not work with optimized code.
@@ -2018,6 +2085,21 @@ void Debug::PrepareForBreakPoints() {
// is used both in GC and non-GC code.
List<Handle<JSFunction> > active_functions(100);
+ // A list of all suspended generators.
+ List<Handle<JSGeneratorObject> > suspended_generators;
+
+ // A list of all generator functions. We need to recompile all functions,
+ // but we don't know until after visiting the whole heap which generator
+ // functions have suspended activations and which do not. As in the case of
+ // functions with activations on the stack, we need to be careful with
+ // generator functions with suspended activations because although they
+ // should be recompiled, recompilation can fail, and we need to avoid
+ // leaving the heap in an inconsistent state.
+ //
+ // We could perhaps avoid this list and instead re-use the GC metadata
+ // links.
+ List<Handle<JSFunction> > generator_functions;
+
{
// We are going to iterate heap to find all functions without
// debug break slots.
@@ -2055,6 +2137,11 @@ void Debug::PrepareForBreakPoints() {
if (function->IsBuiltin()) continue;
if (shared->code()->gc_metadata() == active_code_marker) continue;
+ if (shared->is_generator()) {
+ generator_functions.Add(Handle<JSFunction>(function, isolate_));
+ continue;
+ }
+
Code::Kind kind = function->code()->kind();
if (kind == Code::FUNCTION &&
!function->code()->has_debug_break_slots()) {
@@ -2074,6 +2161,24 @@ void Debug::PrepareForBreakPoints() {
function->shared()->set_code(*lazy_compile);
}
}
+ } else if (obj->IsJSGeneratorObject()) {
+ JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
+ if (!gen->is_suspended()) continue;
+
+ JSFunction* fun = gen->function();
+ ASSERT_EQ(fun->code()->kind(), Code::FUNCTION);
+ if (fun->code()->has_debug_break_slots()) continue;
+
+ int pc_offset = gen->continuation();
+ ASSERT_LT(0, pc_offset);
+
+ int code_offset =
+ ComputeCodeOffsetFromPcOffset(fun->code(), pc_offset);
+
+ // This will be fixed after we recompile the functions.
+ gen->set_continuation(code_offset);
+
+ suspended_generators.Add(Handle<JSGeneratorObject>(gen, isolate_));
}
}
@@ -2084,41 +2189,35 @@ void Debug::PrepareForBreakPoints() {
}
}
+ // Recompile generator functions that have suspended activations, and
+ // relocate those activations.
+ RecompileAndRelocateSuspendedGenerators(suspended_generators);
+
+ // Mark generator functions that didn't have suspended activations for lazy
+ // recompilation. Note that this set does not include any active functions.
+ for (int i = 0; i < generator_functions.length(); i++) {
+ Handle<JSFunction> &function = generator_functions[i];
+ if (function->code()->kind() != Code::FUNCTION) continue;
+ if (function->code()->has_debug_break_slots()) continue;
+ function->set_code(*lazy_compile);
+ function->shared()->set_code(*lazy_compile);
+ }
+
// Now recompile all functions with activation frames and and
- // patch the return address to run in the new compiled code.
+ // patch the return address to run in the new compiled code. It could be
+ // that some active functions were recompiled already by the suspended
+ // generator recompilation pass above; a generator with suspended
+ // activations could also have active activations. That's fine.
for (int i = 0; i < active_functions.length(); i++) {
Handle<JSFunction> function = active_functions[i];
Handle<SharedFunctionInfo> shared(function->shared());
- if (function->code()->kind() == Code::FUNCTION &&
- function->code()->has_debug_break_slots()) {
- // Nothing to do. Function code already had debug break slots.
- continue;
- }
-
// If recompilation is not possible just skip it.
- if (shared->is_toplevel() ||
- !shared->allows_lazy_compilation() ||
- shared->code()->kind() == Code::BUILTIN) {
- continue;
- }
-
- // Make sure that the shared full code is compiled with debug
- // break slots.
- if (!shared->code()->has_debug_break_slots()) {
- // Try to compile the full code with debug break slots. If it
- // fails just keep the current code.
- bool prev_force_debugger_active =
- isolate_->debugger()->force_debugger_active();
- isolate_->debugger()->set_force_debugger_active(true);
- Handle<Code> code = Compiler::GetCodeForDebugging(function);
- function->ReplaceCode(*code);
- isolate_->debugger()->set_force_debugger_active(
- prev_force_debugger_active);
- }
+ if (shared->is_toplevel()) continue;
+ if (!shared->allows_lazy_compilation()) continue;
+ if (shared->code()->kind() == Code::BUILTIN) continue;
- // Keep function code in sync with shared function info.
- function->set_code(shared->code());
+ MaybeRecompileFunctionForDebugging(function);
}
RedirectActivationsToRecompiledCodeOnThread(isolate_,
@@ -2227,10 +2326,10 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
// will compile all inner functions that cannot be compiled without a
// context, because Compiler::BuildFunctionInfo checks whether the
// debugger is active.
- Handle<Code> result = target_function.is_null()
+ MaybeHandle<Code> maybe_result = target_function.is_null()
? Compiler::GetUnoptimizedCode(target)
: Compiler::GetUnoptimizedCode(target_function);
- if (result.is_null()) return isolate_->heap()->undefined_value();
+ if (maybe_result.is_null()) return isolate_->heap()->undefined_value();
}
} // End while loop.
@@ -2463,14 +2562,14 @@ void Debug::ClearMirrorCache() {
// Clear the mirror cache.
Handle<String> function_name = isolate_->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("ClearMirrorCache"));
- Handle<Object> fun(
- isolate_->global_object()->GetPropertyNoExceptionThrown(*function_name),
- isolate_);
+ Handle<Object> fun = Object::GetProperty(
+ isolate_->global_object(), function_name).ToHandleChecked();
ASSERT(fun->IsJSFunction());
- bool caught_exception;
- Execution::TryCall(Handle<JSFunction>::cast(fun),
+ Execution::TryCall(
+ Handle<JSFunction>::cast(fun),
Handle<JSObject>(Debug::debug_context()->global_object()),
- 0, NULL, &caught_exception);
+ 0,
+ NULL);
}
@@ -2591,113 +2690,82 @@ Debugger::Debugger(Isolate* isolate)
Debugger::~Debugger() {}
-Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
- int argc,
- Handle<Object> argv[],
- bool* caught_exception) {
+MaybeHandle<Object> Debugger::MakeJSObject(
+ Vector<const char> constructor_name,
+ int argc,
+ Handle<Object> argv[]) {
ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
// Create the execution state object.
Handle<String> constructor_str =
isolate_->factory()->InternalizeUtf8String(constructor_name);
ASSERT(!constructor_str.is_null());
- Handle<Object> constructor(
- isolate_->global_object()->GetPropertyNoExceptionThrown(*constructor_str),
- isolate_);
+ Handle<Object> constructor = Object::GetProperty(
+ isolate_->global_object(), constructor_str).ToHandleChecked();
ASSERT(constructor->IsJSFunction());
- if (!constructor->IsJSFunction()) {
- *caught_exception = true;
- return isolate_->factory()->undefined_value();
- }
- Handle<Object> js_object = Execution::TryCall(
+ if (!constructor->IsJSFunction()) return MaybeHandle<Object>();
+ return Execution::TryCall(
Handle<JSFunction>::cast(constructor),
Handle<JSObject>(isolate_->debug()->debug_context()->global_object()),
argc,
- argv,
- caught_exception);
- return js_object;
+ argv);
}
-Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
+MaybeHandle<Object> Debugger::MakeExecutionState() {
// Create the execution state object.
Handle<Object> break_id = isolate_->factory()->NewNumberFromInt(
isolate_->debug()->break_id());
Handle<Object> argv[] = { break_id };
- return MakeJSObject(CStrVector("MakeExecutionState"),
- ARRAY_SIZE(argv),
- argv,
- caught_exception);
+ return MakeJSObject(CStrVector("MakeExecutionState"), ARRAY_SIZE(argv), argv);
}
-Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
- Handle<Object> break_points_hit,
- bool* caught_exception) {
+MaybeHandle<Object> Debugger::MakeBreakEvent(Handle<Object> break_points_hit) {
+ Handle<Object> exec_state;
+ if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>();
// Create the new break event object.
Handle<Object> argv[] = { exec_state, break_points_hit };
- return MakeJSObject(CStrVector("MakeBreakEvent"),
- ARRAY_SIZE(argv),
- argv,
- caught_exception);
+ return MakeJSObject(CStrVector("MakeBreakEvent"), ARRAY_SIZE(argv), argv);
}
-Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
- Handle<Object> exception,
- bool uncaught,
- bool* caught_exception) {
- Factory* factory = isolate_->factory();
+MaybeHandle<Object> Debugger::MakeExceptionEvent(Handle<Object> exception,
+ bool uncaught,
+ Handle<Object> promise) {
+ Handle<Object> exec_state;
+ if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>();
// Create the new exception event object.
Handle<Object> argv[] = { exec_state,
exception,
- factory->ToBoolean(uncaught) };
- return MakeJSObject(CStrVector("MakeExceptionEvent"),
- ARRAY_SIZE(argv),
- argv,
- caught_exception);
+ isolate_->factory()->ToBoolean(uncaught),
+ promise };
+ return MakeJSObject(CStrVector("MakeExceptionEvent"), ARRAY_SIZE(argv), argv);
}
-Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
- bool* caught_exception) {
- // Create the new function event object.
- Handle<Object> argv[] = { function };
- return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
- ARRAY_SIZE(argv),
- argv,
- caught_exception);
-}
-
-
-Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
- bool before,
- bool* caught_exception) {
- Factory* factory = isolate_->factory();
+MaybeHandle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
+ bool before) {
+ Handle<Object> exec_state;
+ if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>();
// Create the compile event object.
- Handle<Object> exec_state = MakeExecutionState(caught_exception);
- Handle<Object> script_wrapper = GetScriptWrapper(script);
+ Handle<Object> script_wrapper = Script::GetWrapper(script);
Handle<Object> argv[] = { exec_state,
script_wrapper,
- factory->ToBoolean(before) };
- return MakeJSObject(CStrVector("MakeCompileEvent"),
- ARRAY_SIZE(argv),
- argv,
- caught_exception);
+ isolate_->factory()->ToBoolean(before) };
+ return MakeJSObject(CStrVector("MakeCompileEvent"), ARRAY_SIZE(argv), argv);
}
-Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
- bool* caught_exception) {
+MaybeHandle<Object> Debugger::MakeScriptCollectedEvent(int id) {
+ Handle<Object> exec_state;
+ if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>();
// Create the script collected event object.
- Handle<Object> exec_state = MakeExecutionState(caught_exception);
Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id), isolate_);
Handle<Object> argv[] = { exec_state, id_object };
- return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
- ARRAY_SIZE(argv),
- argv,
- caught_exception);
+ return MakeJSObject(
+ CStrVector("MakeScriptCollectedEvent"), ARRAY_SIZE(argv), argv);
}
@@ -2709,6 +2777,9 @@ void Debugger::OnException(Handle<Object> exception, bool uncaught) {
if (debug->InDebugger()) return;
if (!Debugger::EventActive(v8::Exception)) return;
+ Handle<Object> promise = debug->GetPromiseForUncaughtException();
+ uncaught |= !promise->IsUndefined();
+
// Bail out if exception breaks are not active
if (uncaught) {
// Uncaught exceptions are reported by either flags.
@@ -2725,16 +2796,12 @@ void Debugger::OnException(Handle<Object> exception, bool uncaught) {
// Clear all current stepping setup.
debug->ClearStepping();
+
// Create the event data object.
- bool caught_exception = false;
- Handle<Object> exec_state = MakeExecutionState(&caught_exception);
Handle<Object> event_data;
- if (!caught_exception) {
- event_data = MakeExceptionEvent(exec_state, exception, uncaught,
- &caught_exception);
- }
// Bail out and don't call debugger if exception.
- if (caught_exception) {
+ if (!MakeExceptionEvent(
+ exception, uncaught, promise).ToHandle(&event_data)) {
return;
}
@@ -2758,17 +2825,9 @@ void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
// Create the event data object.
- bool caught_exception = false;
- Handle<Object> exec_state = MakeExecutionState(&caught_exception);
Handle<Object> event_data;
- if (!caught_exception) {
- event_data = MakeBreakEvent(exec_state, break_points_hit,
- &caught_exception);
- }
// Bail out and don't call debugger if exception.
- if (caught_exception) {
- return;
- }
+ if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return;
// Process debug event.
ProcessDebugEvent(v8::Break,
@@ -2790,12 +2849,9 @@ void Debugger::OnBeforeCompile(Handle<Script> script) {
if (debugger.FailedToEnter()) return;
// Create the event data object.
- bool caught_exception = false;
- Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
+ Handle<Object> event_data;
// Bail out and don't call debugger if exception.
- if (caught_exception) {
- return;
- }
+ if (!MakeCompileEvent(script, true).ToHandle(&event_data)) return;
// Process debug event.
ProcessDebugEvent(v8::BeforeCompile,
@@ -2833,11 +2889,10 @@ void Debugger::OnAfterCompile(Handle<Script> script,
Handle<String> update_script_break_points_string =
isolate_->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("UpdateScriptBreakPoints"));
+ Handle<GlobalObject> debug_global(debug->debug_context()->global_object());
Handle<Object> update_script_break_points =
- Handle<Object>(
- debug->debug_context()->global_object()->GetPropertyNoExceptionThrown(
- *update_script_break_points_string),
- isolate_);
+ Object::GetProperty(
+ debug_global, update_script_break_points_string).ToHandleChecked();
if (!update_script_break_points->IsJSFunction()) {
return;
}
@@ -2845,17 +2900,14 @@ void Debugger::OnAfterCompile(Handle<Script> script,
// Wrap the script object in a proper JS object before passing it
// to JavaScript.
- Handle<JSValue> wrapper = GetScriptWrapper(script);
+ Handle<Object> wrapper = Script::GetWrapper(script);
// Call UpdateScriptBreakPoints expect no exceptions.
- bool caught_exception;
Handle<Object> argv[] = { wrapper };
- Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
- isolate_->js_builtins_object(),
- ARRAY_SIZE(argv),
- argv,
- &caught_exception);
- if (caught_exception) {
+ if (Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
+ isolate_->js_builtins_object(),
+ ARRAY_SIZE(argv),
+ argv).is_null()) {
return;
}
// Bail out based on state or if there is no listener for this event
@@ -2863,17 +2915,12 @@ void Debugger::OnAfterCompile(Handle<Script> script,
if (!Debugger::EventActive(v8::AfterCompile)) return;
// Create the compile state object.
- Handle<Object> event_data = MakeCompileEvent(script,
- false,
- &caught_exception);
+ Handle<Object> event_data;
// Bail out and don't call debugger if exception.
- if (caught_exception) {
- return;
- }
+ if (!MakeCompileEvent(script, false).ToHandle(&event_data)) return;
+
// Process debug event.
- ProcessDebugEvent(v8::AfterCompile,
- Handle<JSObject>::cast(event_data),
- true);
+ ProcessDebugEvent(v8::AfterCompile, Handle<JSObject>::cast(event_data), true);
}
@@ -2890,13 +2937,9 @@ void Debugger::OnScriptCollected(int id) {
if (debugger.FailedToEnter()) return;
// Create the script collected state object.
- bool caught_exception = false;
- Handle<Object> event_data = MakeScriptCollectedEvent(id,
- &caught_exception);
+ Handle<Object> event_data;
// Bail out and don't call debugger if exception.
- if (caught_exception) {
- return;
- }
+ if (!MakeScriptCollectedEvent(id).ToHandle(&event_data)) return;
// Process debug event.
ProcessDebugEvent(v8::ScriptCollected,
@@ -2916,11 +2959,10 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event,
}
// Create the execution state.
- bool caught_exception = false;
- Handle<Object> exec_state = MakeExecutionState(&caught_exception);
- if (caught_exception) {
- return;
- }
+ Handle<Object> exec_state;
+ // Bail out and don't call debugger if exception.
+ if (!MakeExecutionState().ToHandle(&exec_state)) return;
+
// First notify the message handler if any.
if (message_handler_ != NULL) {
NotifyMessageHandler(event,
@@ -2991,12 +3033,10 @@ void Debugger::CallJSEventCallback(v8::DebugEvent event,
exec_state,
event_data,
event_listener_data_ };
- bool caught_exception;
Execution::TryCall(fun,
isolate_->global_object(),
ARRAY_SIZE(argv),
- argv,
- &caught_exception);
+ argv);
// Silently ignore exceptions from debug event listeners.
}
@@ -3248,7 +3288,8 @@ void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
void Debugger::ListenersChanged() {
- if (IsDebuggerActive()) {
+ bool active = IsDebuggerActive();
+ if (active) {
// Disable the compilation cache when the debugger is active.
isolate_->compilation_cache()->Disable();
debugger_unload_pending_ = false;
@@ -3350,9 +3391,8 @@ bool Debugger::IsDebuggerActive() {
}
-Handle<Object> Debugger::Call(Handle<JSFunction> fun,
- Handle<Object> data,
- bool* pending_exception) {
+MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun,
+ Handle<Object> data) {
// When calling functions in the debugger prevent it from beeing unloaded.
Debugger::never_unload_debugger_ = true;
@@ -3363,22 +3403,19 @@ Handle<Object> Debugger::Call(Handle<JSFunction> fun,
}
// Create the execution state.
- bool caught_exception = false;
- Handle<Object> exec_state = MakeExecutionState(&caught_exception);
- if (caught_exception) {
+ Handle<Object> exec_state;
+ if (!MakeExecutionState().ToHandle(&exec_state)) {
return isolate_->factory()->undefined_value();
}
Handle<Object> argv[] = { exec_state, data };
- Handle<Object> result = Execution::Call(
+ return Execution::Call(
isolate_,
fun,
Handle<Object>(isolate_->debug()->debug_context_->global_proxy(),
isolate_),
ARRAY_SIZE(argv),
- argv,
- pending_exception);
- return result;
+ argv);
}
@@ -3397,7 +3434,7 @@ bool Debugger::StartAgent(const char* name, int port,
// Once become suspended, V8 will stay so indefinitely long, until remote
// debugger connects and issues "continue" command.
Debugger::message_handler_ = StubMessageHandler2;
- v8::Debug::DebugBreak();
+ v8::Debug::DebugBreak(reinterpret_cast<v8::Isolate*>(isolate_));
}
if (agent_ == NULL) {
@@ -3597,20 +3634,21 @@ v8::Handle<v8::Object> MessageImpl::GetEventData() const {
v8::Handle<v8::String> MessageImpl::GetJSON() const {
- v8::EscapableHandleScope scope(
- reinterpret_cast<v8::Isolate*>(event_data_->GetIsolate()));
+ Isolate* isolate = event_data_->GetIsolate();
+ v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
if (IsEvent()) {
// Call toJSONProtocol on the debug event object.
- Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
+ Handle<Object> fun = Object::GetProperty(
+ isolate, event_data_, "toJSONProtocol").ToHandleChecked();
if (!fun->IsJSFunction()) {
return v8::Handle<v8::String>();
}
- bool caught_exception;
- Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
- event_data_,
- 0, NULL, &caught_exception);
- if (caught_exception || !json->IsString()) {
+
+ 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 scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
@@ -3815,6 +3853,4 @@ void MessageDispatchHelperThread::Run() {
}
}
-#endif // ENABLE_DEBUGGER_SUPPORT
-
} } // namespace v8::internal