diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2014-05-12 05:07:46 +0200 |
---|---|---|
committer | Fedor Indutny <fedor@indutny.com> | 2014-06-12 17:46:17 -0700 |
commit | 3a280b2034e3ea438cd3a2e7acd1a4cd40112ac5 (patch) | |
tree | ae194faf83fd22ad890b421c2ebd537db1a52534 /deps/v8/src/debug.cc | |
parent | 5413d9abe0df7e22bdb650a65f4c0ac462bbe147 (diff) | |
download | node-new-3a280b2034e3ea438cd3a2e7acd1a4cd40112ac5.tar.gz |
deps: upgrade v8 to 3.26.33
Signed-off-by: Fedor Indutny <fedor@indutny.com>
Diffstat (limited to 'deps/v8/src/debug.cc')
-rw-r--r-- | deps/v8/src/debug.cc | 650 |
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 |