| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "v8.h" | 5 #include "v8.h" |
| 6 | 6 |
| 7 #include "api.h" | 7 #include "api.h" |
| 8 #include "arguments.h" | 8 #include "arguments.h" |
| 9 #include "bootstrapper.h" | 9 #include "bootstrapper.h" |
| 10 #include "code-stubs.h" | 10 #include "code-stubs.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 isolate_(isolate) { | 42 isolate_(isolate) { |
| 43 memset(registers_, 0, sizeof(JSCallerSavedBuffer)); | 43 memset(registers_, 0, sizeof(JSCallerSavedBuffer)); |
| 44 ThreadInit(); | 44 ThreadInit(); |
| 45 } | 45 } |
| 46 | 46 |
| 47 | 47 |
| 48 Debug::~Debug() { | 48 Debug::~Debug() { |
| 49 } | 49 } |
| 50 | 50 |
| 51 | 51 |
| 52 static void PrintLn(v8::Local<v8::Value> value) { | |
| 53 v8::Local<v8::String> s = value->ToString(); | |
| 54 ScopedVector<char> data(s->Utf8Length() + 1); | |
| 55 if (data.start() == NULL) { | |
| 56 V8::FatalProcessOutOfMemory("PrintLn"); | |
| 57 return; | |
| 58 } | |
| 59 s->WriteUtf8(data.start()); | |
| 60 PrintF("%s\n", data.start()); | |
| 61 } | |
| 62 | |
| 63 | |
| 64 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { | 52 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { |
| 65 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); | 53 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); |
| 66 // Isolate::context() may have been NULL when "script collected" event | 54 // Isolate::context() may have been NULL when "script collected" event |
| 67 // occured. | 55 // occured. |
| 68 if (context.is_null()) return v8::Local<v8::Context>(); | 56 if (context.is_null()) return v8::Local<v8::Context>(); |
| 69 Handle<Context> native_context(context->native_context()); | 57 Handle<Context> native_context(context->native_context()); |
| 70 return v8::Utils::ToLocal(native_context); | 58 return v8::Utils::ToLocal(native_context); |
| 71 } | 59 } |
| 72 | 60 |
| 73 | 61 |
| (...skipping 2594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2668 : debugger_access_(isolate->debugger_access()), | 2656 : debugger_access_(isolate->debugger_access()), |
| 2669 event_listener_(Handle<Object>()), | 2657 event_listener_(Handle<Object>()), |
| 2670 event_listener_data_(Handle<Object>()), | 2658 event_listener_data_(Handle<Object>()), |
| 2671 compiling_natives_(false), | 2659 compiling_natives_(false), |
| 2672 is_loading_debugger_(false), | 2660 is_loading_debugger_(false), |
| 2673 live_edit_enabled_(true), | 2661 live_edit_enabled_(true), |
| 2674 never_unload_debugger_(false), | 2662 never_unload_debugger_(false), |
| 2675 force_debugger_active_(false), | 2663 force_debugger_active_(false), |
| 2676 message_handler_(NULL), | 2664 message_handler_(NULL), |
| 2677 debugger_unload_pending_(false), | 2665 debugger_unload_pending_(false), |
| 2678 host_dispatch_handler_(NULL), | |
| 2679 debug_message_dispatch_handler_(NULL), | 2666 debug_message_dispatch_handler_(NULL), |
| 2680 message_dispatch_helper_thread_(NULL), | 2667 message_dispatch_helper_thread_(NULL), |
| 2681 host_dispatch_period_(TimeDelta::FromMilliseconds(100)), | |
| 2682 agent_(NULL), | 2668 agent_(NULL), |
| 2683 command_queue_(isolate->logger(), kQueueInitialSize), | 2669 command_queue_(isolate->logger(), kQueueInitialSize), |
| 2684 command_received_(0), | 2670 command_received_(0), |
| 2685 event_command_queue_(isolate->logger(), kQueueInitialSize), | 2671 event_command_queue_(isolate->logger(), kQueueInitialSize), |
| 2686 isolate_(isolate) { | 2672 isolate_(isolate) { |
| 2687 } | 2673 } |
| 2688 | 2674 |
| 2689 | 2675 |
| 2690 Debugger::~Debugger() {} | 2676 Debugger::~Debugger() {} |
| 2691 | 2677 |
| (...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3061 | 3047 |
| 3062 // Clear the flag indicating that the debugger should be unloaded. | 3048 // Clear the flag indicating that the debugger should be unloaded. |
| 3063 debugger_unload_pending_ = false; | 3049 debugger_unload_pending_ = false; |
| 3064 } | 3050 } |
| 3065 | 3051 |
| 3066 | 3052 |
| 3067 void Debugger::NotifyMessageHandler(v8::DebugEvent event, | 3053 void Debugger::NotifyMessageHandler(v8::DebugEvent event, |
| 3068 Handle<JSObject> exec_state, | 3054 Handle<JSObject> exec_state, |
| 3069 Handle<JSObject> event_data, | 3055 Handle<JSObject> event_data, |
| 3070 bool auto_continue) { | 3056 bool auto_continue) { |
| 3071 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(isolate_); | |
| 3072 HandleScope scope(isolate_); | 3057 HandleScope scope(isolate_); |
| 3073 | 3058 |
| 3074 if (!isolate_->debug()->Load()) return; | 3059 if (!isolate_->debug()->Load()) return; |
| 3075 | 3060 |
| 3076 // Process the individual events. | 3061 // Process the individual events. |
| 3077 bool sendEventMessage = false; | 3062 bool sendEventMessage = false; |
| 3078 switch (event) { | 3063 switch (event) { |
| 3079 case v8::Break: | 3064 case v8::Break: |
| 3080 case v8::BreakForCommand: | 3065 case v8::BreakForCommand: |
| 3081 sendEventMessage = !auto_continue; | 3066 sendEventMessage = !auto_continue; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3115 } | 3100 } |
| 3116 | 3101 |
| 3117 // If auto continue don't make the event cause a break, but process messages | 3102 // If auto continue don't make the event cause a break, but process messages |
| 3118 // in the queue if any. For script collected events don't even process | 3103 // in the queue if any. For script collected events don't even process |
| 3119 // messages in the queue as the execution state might not be what is expected | 3104 // messages in the queue as the execution state might not be what is expected |
| 3120 // by the client. | 3105 // by the client. |
| 3121 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) { | 3106 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) { |
| 3122 return; | 3107 return; |
| 3123 } | 3108 } |
| 3124 | 3109 |
| 3125 v8::TryCatch try_catch; | |
| 3126 | |
| 3127 // DebugCommandProcessor goes here. | 3110 // DebugCommandProcessor goes here. |
| 3128 v8::Local<v8::Object> cmd_processor; | |
| 3129 { | |
| 3130 v8::Local<v8::Object> api_exec_state = | |
| 3131 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)); | |
| 3132 v8::Local<v8::String> fun_name = v8::String::NewFromUtf8( | |
| 3133 isolate, "debugCommandProcessor"); | |
| 3134 v8::Local<v8::Function> fun = | |
| 3135 v8::Local<v8::Function>::Cast(api_exec_state->Get(fun_name)); | |
| 3136 | |
| 3137 v8::Handle<v8::Boolean> running = v8::Boolean::New(isolate, auto_continue); | |
| 3138 static const int kArgc = 1; | |
| 3139 v8::Handle<Value> argv[kArgc] = { running }; | |
| 3140 cmd_processor = v8::Local<v8::Object>::Cast( | |
| 3141 fun->Call(api_exec_state, kArgc, argv)); | |
| 3142 if (try_catch.HasCaught()) { | |
| 3143 PrintLn(try_catch.Exception()); | |
| 3144 return; | |
| 3145 } | |
| 3146 } | |
| 3147 | |
| 3148 bool running = auto_continue; | 3111 bool running = auto_continue; |
| 3149 | 3112 |
| 3113 Handle<Object> cmd_processor_ctor = Object::GetProperty( |
| 3114 isolate_, exec_state, "debugCommandProcessor").ToHandleChecked(); |
| 3115 Handle<Object> ctor_args[] = { isolate_->factory()->ToBoolean(running) }; |
| 3116 Handle<Object> cmd_processor = Execution::Call( |
| 3117 isolate_, cmd_processor_ctor, exec_state, 1, ctor_args).ToHandleChecked(); |
| 3118 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast( |
| 3119 Object::GetProperty( |
| 3120 isolate_, cmd_processor, "processDebugRequest").ToHandleChecked()); |
| 3121 Handle<Object> is_running = Object::GetProperty( |
| 3122 isolate_, cmd_processor, "isRunning").ToHandleChecked(); |
| 3123 |
| 3150 // Process requests from the debugger. | 3124 // Process requests from the debugger. |
| 3151 while (true) { | 3125 do { |
| 3152 // Wait for new command in the queue. | 3126 // Wait for new command in the queue. |
| 3153 if (Debugger::host_dispatch_handler_) { | 3127 command_received_.Wait(); |
| 3154 // In case there is a host dispatch - do periodic dispatches. | |
| 3155 if (!command_received_.WaitFor(host_dispatch_period_)) { | |
| 3156 // Timout expired, do the dispatch. | |
| 3157 Debugger::host_dispatch_handler_(); | |
| 3158 continue; | |
| 3159 } | |
| 3160 } else { | |
| 3161 // In case there is no host dispatch - just wait. | |
| 3162 command_received_.Wait(); | |
| 3163 } | |
| 3164 | 3128 |
| 3165 // Get the command from the queue. | 3129 // Get the command from the queue. |
| 3166 CommandMessage command = command_queue_.Get(); | 3130 CommandMessage command = command_queue_.Get(); |
| 3167 isolate_->logger()->DebugTag( | 3131 isolate_->logger()->DebugTag( |
| 3168 "Got request from command queue, in interactive loop."); | 3132 "Got request from command queue, in interactive loop."); |
| 3169 if (!Debugger::IsDebuggerActive()) { | 3133 if (!Debugger::IsDebuggerActive()) { |
| 3170 // Delete command text and user data. | 3134 // Delete command text and user data. |
| 3171 command.Dispose(); | 3135 command.Dispose(); |
| 3172 return; | 3136 return; |
| 3173 } | 3137 } |
| 3174 | 3138 |
| 3175 // Invoke JavaScript to process the debug request. | 3139 Vector<const uc16> command_text( |
| 3176 v8::Local<v8::String> fun_name; | 3140 const_cast<const uc16*>(command.text().start()), |
| 3177 v8::Local<v8::Function> fun; | 3141 command.text().length()); |
| 3178 v8::Local<v8::Value> request; | 3142 Handle<String> request_text = isolate_->factory()->NewStringFromTwoByte( |
| 3179 v8::TryCatch try_catch; | 3143 command_text).ToHandleChecked(); |
| 3180 fun_name = v8::String::NewFromUtf8(isolate, "processDebugRequest"); | 3144 Handle<Object> request_args[] = { request_text }; |
| 3181 fun = v8::Local<v8::Function>::Cast(cmd_processor->Get(fun_name)); | 3145 Handle<Object> exception; |
| 3146 Handle<Object> answer_value; |
| 3147 Handle<String> answer; |
| 3148 MaybeHandle<Object> maybe_result = Execution::TryCall( |
| 3149 process_debug_request, cmd_processor, 1, request_args, &exception); |
| 3182 | 3150 |
| 3183 request = v8::String::NewFromTwoByte(isolate, command.text().start(), | 3151 if (maybe_result.ToHandle(&answer_value)) { |
| 3184 v8::String::kNormalString, | 3152 if (answer_value->IsUndefined()) { |
| 3185 command.text().length()); | 3153 answer = isolate_->factory()->empty_string(); |
| 3186 static const int kArgc = 1; | |
| 3187 v8::Handle<Value> argv[kArgc] = { request }; | |
| 3188 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv); | |
| 3189 | |
| 3190 // Get the response. | |
| 3191 v8::Local<v8::String> response; | |
| 3192 if (!try_catch.HasCaught()) { | |
| 3193 // Get response string. | |
| 3194 if (!response_val->IsUndefined()) { | |
| 3195 response = v8::Local<v8::String>::Cast(response_val); | |
| 3196 } else { | 3154 } else { |
| 3197 response = v8::String::NewFromUtf8(isolate, ""); | 3155 answer = Handle<String>::cast(answer_value); |
| 3198 } | 3156 } |
| 3199 | 3157 |
| 3200 // Log the JSON request/response. | 3158 // Log the JSON request/response. |
| 3201 if (FLAG_trace_debug_json) { | 3159 if (FLAG_trace_debug_json) { |
| 3202 PrintLn(request); | 3160 PrintF("%s\n", request_text->ToCString().get()); |
| 3203 PrintLn(response); | 3161 PrintF("%s\n", answer->ToCString().get()); |
| 3204 } | 3162 } |
| 3205 | 3163 |
| 3206 // Get the running state. | 3164 Handle<Object> is_running_args[] = { answer }; |
| 3207 fun_name = v8::String::NewFromUtf8(isolate, "isRunning"); | 3165 maybe_result = Execution::Call( |
| 3208 fun = v8::Local<v8::Function>::Cast(cmd_processor->Get(fun_name)); | 3166 isolate_, is_running, cmd_processor, 1, is_running_args); |
| 3209 static const int kArgc = 1; | 3167 running = maybe_result.ToHandleChecked()->IsTrue(); |
| 3210 v8::Handle<Value> argv[kArgc] = { response }; | |
| 3211 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv); | |
| 3212 if (!try_catch.HasCaught()) { | |
| 3213 running = running_val->ToBoolean()->Value(); | |
| 3214 } | |
| 3215 } else { | 3168 } else { |
| 3216 // In case of failure the result text is the exception text. | 3169 answer = Handle<String>::cast( |
| 3217 response = try_catch.Exception()->ToString(); | 3170 Execution::ToString(isolate_, exception).ToHandleChecked()); |
| 3218 } | 3171 } |
| 3219 | 3172 |
| 3220 // Return the result. | 3173 // Return the result. |
| 3221 MessageImpl message = MessageImpl::NewResponse( | 3174 MessageImpl message = MessageImpl::NewResponse( |
| 3222 event, | 3175 event, running, exec_state, event_data, answer, command.client_data()); |
| 3223 running, | |
| 3224 Handle<JSObject>::cast(exec_state), | |
| 3225 Handle<JSObject>::cast(event_data), | |
| 3226 Handle<String>(Utils::OpenHandle(*response)), | |
| 3227 command.client_data()); | |
| 3228 InvokeMessageHandler(message); | 3176 InvokeMessageHandler(message); |
| 3229 command.Dispose(); | 3177 command.Dispose(); |
| 3230 | 3178 |
| 3231 // Return from debug event processing if either the VM is put into the | 3179 // Return from debug event processing if either the VM is put into the |
| 3232 // running state (through a continue command) or auto continue is active | 3180 // running state (through a continue command) or auto continue is active |
| 3233 // and there are no more commands queued. | 3181 // and there are no more commands queued. |
| 3234 if (running && !HasCommands()) { | 3182 } while (!running || HasCommands()); |
| 3235 return; | |
| 3236 } | |
| 3237 } | |
| 3238 } | 3183 } |
| 3239 | 3184 |
| 3240 | 3185 |
| 3241 void Debugger::SetEventListener(Handle<Object> callback, | 3186 void Debugger::SetEventListener(Handle<Object> callback, |
| 3242 Handle<Object> data) { | 3187 Handle<Object> data) { |
| 3243 HandleScope scope(isolate_); | 3188 HandleScope scope(isolate_); |
| 3244 GlobalHandles* global_handles = isolate_->global_handles(); | 3189 GlobalHandles* global_handles = isolate_->global_handles(); |
| 3245 | 3190 |
| 3246 // Clear the global handles for the event listener and the event listener data | 3191 // Clear the global handles for the event listener and the event listener data |
| 3247 // object. | 3192 // object. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3295 debugger_unload_pending_ = false; | 3240 debugger_unload_pending_ = false; |
| 3296 } else { | 3241 } else { |
| 3297 isolate_->compilation_cache()->Enable(); | 3242 isolate_->compilation_cache()->Enable(); |
| 3298 // Unload the debugger if event listener and message handler cleared. | 3243 // Unload the debugger if event listener and message handler cleared. |
| 3299 // Schedule this for later, because we may be in non-V8 thread. | 3244 // Schedule this for later, because we may be in non-V8 thread. |
| 3300 debugger_unload_pending_ = true; | 3245 debugger_unload_pending_ = true; |
| 3301 } | 3246 } |
| 3302 } | 3247 } |
| 3303 | 3248 |
| 3304 | 3249 |
| 3305 void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler, | |
| 3306 TimeDelta period) { | |
| 3307 host_dispatch_handler_ = handler; | |
| 3308 host_dispatch_period_ = period; | |
| 3309 } | |
| 3310 | |
| 3311 | |
| 3312 void Debugger::SetDebugMessageDispatchHandler( | 3250 void Debugger::SetDebugMessageDispatchHandler( |
| 3313 v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) { | 3251 v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) { |
| 3314 LockGuard<Mutex> lock_guard(&dispatch_handler_access_); | 3252 LockGuard<Mutex> lock_guard(&dispatch_handler_access_); |
| 3315 debug_message_dispatch_handler_ = handler; | 3253 debug_message_dispatch_handler_ = handler; |
| 3316 | 3254 |
| 3317 if (provide_locker && message_dispatch_helper_thread_ == NULL) { | 3255 if (provide_locker && message_dispatch_helper_thread_ == NULL) { |
| 3318 message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_); | 3256 message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_); |
| 3319 message_dispatch_helper_thread_->Start(); | 3257 message_dispatch_helper_thread_->Start(); |
| 3320 } | 3258 } |
| 3321 } | 3259 } |
| (...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3847 already_signalled_ = false; | 3785 already_signalled_ = false; |
| 3848 } | 3786 } |
| 3849 { | 3787 { |
| 3850 Locker locker(reinterpret_cast<v8::Isolate*>(isolate_)); | 3788 Locker locker(reinterpret_cast<v8::Isolate*>(isolate_)); |
| 3851 isolate_->debugger()->CallMessageDispatchHandler(); | 3789 isolate_->debugger()->CallMessageDispatchHandler(); |
| 3852 } | 3790 } |
| 3853 } | 3791 } |
| 3854 } | 3792 } |
| 3855 | 3793 |
| 3856 } } // namespace v8::internal | 3794 } } // namespace v8::internal |
| OLD | NEW |