OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 #include "config.h" | |
31 #include "bindings/dart/DartDebugServer.h" | |
32 | |
33 #include "DartDebugHooksSource.h" | |
34 #include "bindings/dart/DartController.h" | |
35 #include "bindings/dart/DartHandleProxy.h" | |
36 #include "bindings/dart/DartUtilities.h" | |
37 #include "bindings/dart/V8Converter.h" | |
38 #include "bindings/v8/PageScriptDebugServer.h" | |
39 #include "bindings/v8/ScriptController.h" | |
40 #include "bindings/dart/DartScriptState.h" | |
41 #include "bindings/v8/V8Binding.h" | |
42 #include "core/dom/Document.h" | |
43 #include "core/frame/DOMWindow.h" | |
44 #include "core/inspector/InspectorController.h" | |
45 #include "core/inspector/InspectorDebuggerAgent.h" | |
46 #include "core/inspector/InspectorInstrumentation.h" | |
47 #include "core/inspector/InstrumentingAgents.h" | |
48 #include "core/page/Page.h" | |
49 #include "platform/Logging.h" | |
50 | |
51 #include "wtf/HashMap.h" | |
52 #include "wtf/Vector.h" | |
53 #include <v8-debug.h> | |
54 | |
55 | |
56 namespace WebCore { | |
57 | |
58 class V8EventDetails : public v8::Debug::EventDetails { | |
59 public: | |
60 V8EventDetails(v8::DebugEvent event, v8::Handle<v8::Object> executionState,
v8::Handle<v8::Object> eventData) | |
61 : m_event(event) | |
62 , m_executionState(executionState) | |
63 , m_eventData(eventData) | |
64 { | |
65 LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame()
; | |
66 m_eventContext = toV8Context(v8::Isolate::GetCurrent(), frame, DOMWrappe
rWorld::mainWorld()); | |
67 } | |
68 | |
69 virtual v8::DebugEvent GetEvent() const { return m_event; } | |
70 virtual v8::Handle<v8::Object> GetExecutionState() const { return m_executio
nState; } | |
71 virtual v8::Handle<v8::Object> GetEventData() const { return m_eventData; } | |
72 virtual v8::Handle<v8::Context> GetEventContext() const { return m_eventCont
ext; } | |
73 virtual v8::Handle<v8::Value> GetCallbackData() const { return v8::Undefined
(v8::Isolate::GetCurrent()); } | |
74 virtual v8::Debug::ClientData* GetClientData() const { return 0; } | |
75 | |
76 private: | |
77 v8::DebugEvent m_event; | |
78 v8::Handle<v8::Object> m_executionState; | |
79 v8::Handle<v8::Object> m_eventData; | |
80 v8::Handle<v8::Context> m_eventContext; | |
81 }; | |
82 | |
83 template<typename T> | |
84 class HandleMap { | |
85 public: | |
86 HandleMap() : m_lastHandle(0) | |
87 { | |
88 } | |
89 | |
90 int add(T value) | |
91 { | |
92 int handle = ++m_lastHandle; | |
93 m_handleToValueMap.set(handle, value); | |
94 m_valueToHandleMap.set(value, handle); | |
95 return handle; | |
96 } | |
97 | |
98 T get(int handle) | |
99 { | |
100 return m_handleToValueMap.get(handle); | |
101 } | |
102 | |
103 int getByValue(T value) | |
104 { | |
105 ASSERT(m_valueToHandleMap.contains(value)); | |
106 return m_valueToHandleMap.get(value); | |
107 } | |
108 | |
109 T remove(int handle) | |
110 { | |
111 T value = m_handleToValueMap.take(handle); | |
112 m_valueToHandleMap.remove(value); | |
113 return value; | |
114 } | |
115 | |
116 int removeByValue(T value) | |
117 { | |
118 int handle = m_valueToHandleMap.take(value); | |
119 m_handleToValueMap.remove(handle); | |
120 return handle; | |
121 } | |
122 | |
123 void copyValues(Vector<T>& values) | |
124 { | |
125 copyKeysToVector(m_valueToHandleMap, values); | |
126 } | |
127 | |
128 private: | |
129 int m_lastHandle; | |
130 HashMap<int, T> m_handleToValueMap; | |
131 HashMap<T, int> m_valueToHandleMap; | |
132 }; | |
133 | |
134 static HandleMap<Dart_Isolate>& isolateMap() | |
135 { | |
136 DEFINE_STATIC_LOCAL(HandleMap<Dart_Isolate>, map, ()); | |
137 return map; | |
138 } | |
139 | |
140 DartDebugServer& DartDebugServer::shared() | |
141 { | |
142 DEFINE_STATIC_LOCAL(DartDebugServer, server, ()); | |
143 return server; | |
144 } | |
145 | |
146 DartDebugServer::DartDebugServer() | |
147 { | |
148 } | |
149 | |
150 void DartDebugServer::registerIsolate(Dart_Isolate isolate) | |
151 { | |
152 { | |
153 DartIsolateScope scope(isolate); | |
154 DartApiScope apiScope; | |
155 Dart_SetBreakpointHandler(breakpointHandler); | |
156 Dart_SetExceptionThrownHandler(exceptionHandler); | |
157 Dart_SetIsolateEventHandler(isolateEventHandler); | |
158 } | |
159 | |
160 ensureHooksInstalled(); | |
161 | |
162 int isolateHandle = isolateMap().add(isolate); | |
163 | |
164 V8Scope v8Scope(0, v8::Debug::GetDebugContext()); | |
165 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); | |
166 v8::Local<v8::Function> registerIsolate = v8::Local<v8::Function>::Cast(dart
DebugObject()->Get(v8::String::NewFromUtf8(v8Isolate, "registerIsolate"))); | |
167 v8::Handle<v8::Value> args[] = { v8::Number::New(v8Isolate, isolateHandle) }
; | |
168 registerIsolate->Call(dartDebugObject(), 1, args); | |
169 } | |
170 | |
171 void DartDebugServer::debugBreak() | |
172 { | |
173 Vector<Dart_Isolate> isolates; | |
174 isolateMap().copyValues(isolates); | |
175 for (Vector<Dart_Isolate>::iterator it = isolates.begin(); it != isolates.en
d(); ++it) { | |
176 Dart_Isolate isolate = *it; | |
177 if (!m_interruptCalled.contains(isolate)) { | |
178 m_interruptCalled.add(isolate); | |
179 Dart_InterruptIsolate(isolate); | |
180 } | |
181 m_interruptCancelled.remove(isolate); | |
182 } | |
183 } | |
184 | |
185 void DartDebugServer::cancelDebugBreak() | |
186 { | |
187 // FIXME: it would be nice if the DartVM provided an API to directly cancel | |
188 // a debug break call like V8 does. | |
189 for (HashSet<Dart_Isolate>::iterator it = m_interruptCalled.begin(); it != m
_interruptCalled.end(); ++it) { | |
190 m_interruptCancelled.add(*it); | |
191 } | |
192 } | |
193 | |
194 void DartDebugServer::unregisterIsolate(Dart_Isolate isolate) | |
195 { | |
196 int isolateHandle = isolateMap().removeByValue(isolate); | |
197 | |
198 // The constructor for V8Scope expects Dart_InitOnce to have been | |
199 // invoked while it accesses the script execution context | |
200 // (DartUtilities::scriptExecutionContext). The assert below ensures | |
201 // that by making sure the DartDebugObject has been setup. | |
202 ASSERT(!m_dartDebugObject.isEmpty()); | |
203 V8Scope v8Scope(0, v8::Debug::GetDebugContext()); | |
204 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); | |
205 v8::Local<v8::Function> unregisterIsolate = v8::Local<v8::Function>::Cast(da
rtDebugObject()->Get(v8::String::NewFromUtf8(v8Isolate, "unregisterIsolate"))); | |
206 v8::Handle<v8::Value> args[] = { v8::Number::New(v8Isolate, isolateHandle) }
; | |
207 unregisterIsolate->Call(dartDebugObject(), 1, args); | |
208 } | |
209 | |
210 void DartDebugServer::isolateLoaded() | |
211 { | |
212 Page* page = DartUtilities::domWindowForCurrentIsolate()->document()->page()
; | |
213 if (!page || !instrumentationForPage(page)->inspectorDebuggerAgent()) | |
214 return; | |
215 | |
216 ASSERT(Dart_CurrentIsolate()); | |
217 V8Scope v8Scope(DartDOMData::current(), v8::Debug::GetDebugContext()); | |
218 | |
219 int isolateHandle = isolateMap().getByValue(Dart_CurrentIsolate()); | |
220 | |
221 LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame(); | |
222 DartController* controller = DartController::retrieve(frame); | |
223 Vector<DartScriptState*> scriptStates; | |
224 controller->collectScriptStatesForIsolate(Dart_CurrentIsolate(), DartUtiliti
es::currentV8Context(), scriptStates); | |
225 for (size_t i = 0; i< scriptStates.size(); i++) | |
226 InspectorInstrumentation::didCreateIsolatedContext(frame, scriptStates[i
], 0); | |
227 | |
228 ASSERT(!m_dartDebugObject.isEmpty()); | |
229 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); | |
230 v8::Local<v8::Function> isolateLoaded = v8::Local<v8::Function>::Cast(dartDe
bugObject()->Get(v8::String::NewFromUtf8(v8Isolate, "isolateLoaded"))); | |
231 v8::Handle<v8::Value> args[] = { v8::Number::New(v8Isolate, isolateHandle) }
; | |
232 isolateLoaded->Call(dartDebugObject(), 1, args); | |
233 } | |
234 | |
235 void DartDebugServer::disable() | |
236 { | |
237 // Only invoke the disable method when Dart code was executed on the page. | |
238 if (m_dartDebugObject.isEmpty()) | |
239 return; | |
240 V8Scope v8Scope(0, v8::Debug::GetDebugContext()); | |
241 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); | |
242 v8::Local<v8::Function> disable = v8::Local<v8::Function>::Cast(dartDebugObj
ect()->Get(v8::String::NewFromUtf8(v8Isolate, "disable"))); | |
243 disable->Call(dartDebugObject(), 0, 0); | |
244 } | |
245 | |
246 bool lookupTokenLineNumber(const Dart_CodeLocation& location, int* lineNumber, i
nt* columnNumber) | |
247 { | |
248 Dart_Handle info = Dart_ScriptGetTokenInfo(location.library_id, location.scr
ipt_url); | |
249 ASSERT(Dart_IsList(info)); | |
250 intptr_t infoLength = 0; | |
251 Dart_Handle ALLOW_UNUSED result = Dart_ListLength(info, &infoLength); | |
252 ASSERT(!Dart_IsError(result)); | |
253 Dart_Handle elem; | |
254 bool lineStart = true; | |
255 int currentLineNumber = 0; | |
256 for (intptr_t i = 0; i < infoLength; i++) { | |
257 elem = Dart_ListGetAt(info, i); | |
258 if (Dart_IsNull(elem)) { | |
259 lineStart = true; | |
260 } else { | |
261 ASSERT(Dart_IsInteger(elem)); | |
262 Dart_Handle exception = 0; | |
263 int64_t value = DartUtilities::toInteger(elem, exception); | |
264 ASSERT(!exception); | |
265 if (lineStart) { | |
266 // Line number. | |
267 currentLineNumber = value; | |
268 lineStart = false; | |
269 } else { | |
270 // Token offset. | |
271 if (value == location.token_pos) { | |
272 *lineNumber = currentLineNumber; | |
273 ASSERT(i + 1 < infoLength); | |
274 *columnNumber = DartUtilities::toInteger(Dart_ListGetAt(info
, i + 1), exception); | |
275 ASSERT(!exception); | |
276 return true; | |
277 } | |
278 i++; // skip columnNumber. | |
279 } | |
280 } | |
281 } | |
282 return false; | |
283 } | |
284 | |
285 v8::Handle<v8::Object> DartDebugServer::createExecutionState(Dart_StackTrace tra
ce) | |
286 { | |
287 intptr_t length = 0; | |
288 Dart_Handle ALLOW_UNUSED result = Dart_StackTraceLength(trace, &length); | |
289 ASSERT(!Dart_IsError(result)); | |
290 ASSERT(length); | |
291 ASSERT(Dart_CurrentIsolate()); | |
292 int isolateHandle = isolateMap().getByValue(Dart_CurrentIsolate()); | |
293 | |
294 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); | |
295 v8::Local<v8::Array> callFrames = v8::Array::New(v8Isolate, length); | |
296 for (int i = length - 1; i >= 0; --i) { | |
297 Dart_ActivationFrame frame = 0; | |
298 result = Dart_GetActivationFrame(trace, i, &frame); | |
299 ASSERT(!Dart_IsError(result)); | |
300 Dart_Handle functionName = 0; | |
301 Dart_Handle function = 0; | |
302 | |
303 Dart_CodeLocation location; | |
304 result = Dart_ActivationFrameGetLocation(frame, &functionName, &function
, &location); | |
305 int lineNumber = 0; | |
306 int columnNumber = 0; | |
307 lookupTokenLineNumber(location, &lineNumber, &columnNumber); | |
308 ASSERT(!Dart_IsError(result)); | |
309 Dart_Handle libraryURL = Dart_GetLibraryURL(location.library_id); | |
310 ASSERT(!Dart_IsError(libraryURL)); | |
311 Dart_Handle library = Dart_LookupLibrary(libraryURL); | |
312 Dart_Handle localVariablesHandle = Dart_GetLocalVariables(frame); | |
313 | |
314 v8::Local<v8::Object> callFrame = v8::Object::New(v8Isolate); | |
315 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "functionName"), V8Con
verter::stringToV8(functionName)); | |
316 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "functionProxy"), Dart
HandleProxy::create(function)); | |
317 Dart_Handle functionOwner = function; | |
318 // Walk up the chain of function owners until we reach a type or library
handle. | |
319 while (Dart_IsFunction(functionOwner)) | |
320 functionOwner = Dart_FunctionOwner(functionOwner); | |
321 | |
322 if (Dart_IsType(functionOwner)) { | |
323 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "classProxy"), Dar
tHandleProxy::createTypeProxy(functionOwner, true)); | |
324 } | |
325 | |
326 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "scriptURL"), V8Conver
ter::stringToV8(location.script_url)); | |
327 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "lineNumber"), v8::Num
ber::New(v8Isolate, lineNumber - 1)); | |
328 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "columnNumber"), v8::N
umber::New(v8Isolate, columnNumber - 1)); | |
329 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "libraryProxy"), DartH
andleProxy::createLibraryProxy(library, location.library_id, Dart_Null(), true))
; | |
330 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "localScopeProxy"), Da
rtHandleProxy::createLocalScopeProxy( | |
331 localVariablesHandle)); | |
332 { | |
333 v8::Local<v8::Object> librariesMap = v8::Object::New(v8Isolate); | |
334 Dart_Handle libraries = Dart_GetLibraryIds(); | |
335 ASSERT(Dart_IsList(libraries)); | |
336 | |
337 intptr_t librariesLength = 0; | |
338 Dart_Handle ALLOW_UNUSED result = Dart_ListLength(libraries, &librar
iesLength); | |
339 ASSERT(!Dart_IsError(result)); | |
340 for (intptr_t i = 0; i < librariesLength; ++i) { | |
341 Dart_Handle libraryIdHandle = Dart_ListGetAt(libraries, i); | |
342 ASSERT(!Dart_IsError(libraryIdHandle)); | |
343 Dart_Handle exception = 0; | |
344 int64_t libraryId = DartUtilities::toInteger(libraryIdHandle, ex
ception); | |
345 v8::Local<v8::String> libraryName = V8Converter::stringToV8(Dart
_GetLibraryURL(libraryId)); | |
346 v8::Local<v8::Value> libraryProxy = DartHandleProxy::createLibra
ryProxy(Dart_GetLibraryFromId(libraryId), libraryId, Dart_Null(), false); | |
347 librariesMap->Set(libraryName, libraryProxy); | |
348 } | |
349 librariesMap->Set(v8::String::NewFromUtf8(v8Isolate, "__proto__"), v
8::Null(v8Isolate)); | |
350 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "librariesProxy"),
librariesMap); | |
351 } | |
352 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "localVariables"), Dar
tHandleProxy::create(localVariablesHandle)); | |
353 callFrame->Set(v8::String::NewFromUtf8(v8Isolate, "isolateHandle"), v8::
Number::New(v8Isolate, isolateHandle)); | |
354 callFrames->Set(i, callFrame); | |
355 } | |
356 | |
357 ASSERT(!m_dartDebugObject.isEmpty()); | |
358 v8::Handle<v8::Function> executionStateConstructor = v8::Local<v8::Function>
::Cast(dartDebugObject()->Get(v8::String::NewFromUtf8(v8Isolate, "ExecutionState
"))); | |
359 v8::Handle<v8::Value> args[] = { callFrames }; | |
360 return v8::Local<v8::Object>::Cast(executionStateConstructor->CallAsConstruc
tor(1, args)); | |
361 } | |
362 | |
363 void DartDebugServer::breakpointHandler(Dart_IsolateId isolateId, Dart_Breakpoin
t breakpoint, Dart_StackTrace trace) | |
364 { | |
365 DartDebugServer::shared().handleBreakpoint(breakpoint, trace); | |
366 } | |
367 | |
368 void DartDebugServer::handleBreakpoint(Dart_Breakpoint, Dart_StackTrace trace) | |
369 { | |
370 // The constructor for V8Scope expects Dart_InitOnce to have been | |
371 // invoked while it accesses the script execution context | |
372 // (DartUtilities::scriptExecutionContext). The assert below ensures | |
373 // that by making sure the DartDebugObject has been setup. | |
374 ASSERT(!m_dartDebugObject.isEmpty()); | |
375 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); | |
376 V8Scope v8Scope(0, v8::Debug::GetDebugContext()); | |
377 V8Scope v8WorldScope(0, DartUtilities::currentV8Context()); | |
378 V8EventDetails eventDetails(v8::Break, createExecutionState(trace), v8::Obje
ct::New(v8Isolate)); | |
379 PageScriptDebugServer::shared().handleV8DebugEvent(eventDetails); | |
380 } | |
381 | |
382 void DartDebugServer::exceptionHandler(Dart_IsolateId isolateId, Dart_Handle exc
eption, Dart_StackTrace trace) | |
383 { | |
384 DartDebugServer::shared().handleException(exception, trace); | |
385 } | |
386 | |
387 void DartDebugServer::isolateEventHandler(Dart_IsolateId isolateId, Dart_Isolate
Event kind) | |
388 { | |
389 if (kind == kInterrupted) { | |
390 DartDebugServer::shared().handleInterrupted(isolateId); | |
391 } | |
392 } | |
393 | |
394 void DartDebugServer::handleInterrupted(Dart_IsolateId isolateId) | |
395 { | |
396 Dart_Isolate isolate = Dart_GetIsolate(isolateId); | |
397 | |
398 if (isolate) { | |
399 ASSERT(isolate == Dart_CurrentIsolate()); | |
400 ASSERT(m_interruptCalled.contains(isolate)); | |
401 m_interruptCalled.remove(isolate); | |
402 if (m_interruptCancelled.contains(isolate)) { | |
403 m_interruptCancelled.remove(isolate); | |
404 return; | |
405 } | |
406 | |
407 // FIXME: this is a bit of a hack. V8 was also set to pause on the next | |
408 // code execution. If it attempts to pause while in the middle of | |
409 // internal V8 debugger logic it will crash so before we do anything we | |
410 // need to cancel the pending pause sent to V8. | |
411 // Perhaps it would be slightly less hacky to send a message to | |
412 // ScriptDebugServer instructing it to cancel pausing V8. | |
413 v8::Debug::CancelDebugBreak(DartUtilities::currentV8Context()->GetIsolat
e()); | |
414 | |
415 // The user really wants to be paused at the start of the first line of | |
416 // the Dart method not at the method invocation itself. Otherwise, | |
417 // stepping to the next call steps out of the executing Dart code | |
418 // which is not what the user expects. | |
419 Dart_SetStepInto(); | |
420 } | |
421 } | |
422 | |
423 void DartDebugServer::handleException(Dart_Handle exception, Dart_StackTrace tra
ce) | |
424 { | |
425 // The constructor for V8Scope expects Dart_InitOnce to have been | |
426 // invoked while it accesses the script execution context | |
427 // (DartUtilities::scriptExecutionContext). The assert below ensures | |
428 // that by making sure the DartDebugObject has been setup. | |
429 ASSERT(!m_dartDebugObject.isEmpty()); | |
430 V8Scope v8Scope(0, v8::Debug::GetDebugContext()); | |
431 V8Scope v8WorldScope(0, DartUtilities::currentV8Context()); | |
432 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); | |
433 v8::Handle<v8::Function> eventDataConstructor = v8::Local<v8::Function>::Cas
t(dartDebugObject()->Get(v8::String::NewFromUtf8(v8Isolate, "EventData"))); | |
434 v8::Handle<v8::Value> args[] = { DartHandleProxy::create(exception) }; | |
435 v8::Handle<v8::Object> eventData = v8::Local<v8::Object>::Cast(eventDataCons
tructor->CallAsConstructor(1, args)); | |
436 V8EventDetails eventDetails(v8::Exception, createExecutionState(trace), even
tData); | |
437 PageScriptDebugServer::shared().handleV8DebugEvent(eventDetails); | |
438 } | |
439 | |
440 static void handleDebugEvent(const v8::FunctionCallbackInfo<v8::Value>& args) | |
441 { | |
442 v8::DebugEvent event = static_cast<v8::DebugEvent>(args[0]->Int32Value()); | |
443 v8::Local<v8::Object> executionState = v8::Local<v8::Object>::Cast(args[1]); | |
444 v8::Local<v8::Object> eventData = v8::Local<v8::Object>::Cast(args[2]); | |
445 V8EventDetails eventDetails(event, executionState, eventData); | |
446 PageScriptDebugServer::shared().handleV8DebugEvent(eventDetails); | |
447 } | |
448 | |
449 static void scriptsForIsolate(const v8::FunctionCallbackInfo<v8::Value>& args) | |
450 { | |
451 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); | |
452 v8::Handle<v8::Array> v8Scripts = v8::Array::New(v8Isolate); | |
453 | |
454 Dart_Isolate isolate = isolateMap().get(args[0]->Int32Value()); | |
455 | |
456 DartIsolateScope scope(isolate); | |
457 DartApiScope apiScope; | |
458 | |
459 LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame(); | |
460 v8::Handle<v8::Value> contextData = toV8Context(v8Isolate, frame, DOMWrapper
World::mainWorld())->GetEmbedderData(0); | |
461 | |
462 Dart_Handle libraries = Dart_GetLibraryIds(); | |
463 ASSERT(Dart_IsList(libraries)); | |
464 | |
465 intptr_t librariesLength = 0; | |
466 Dart_Handle ALLOW_UNUSED result = Dart_ListLength(libraries, &librariesLengt
h); | |
467 ASSERT(!Dart_IsError(result)); | |
468 for (intptr_t i = 0; i < librariesLength; ++i) { | |
469 Dart_Handle libraryIdHandle = Dart_ListGetAt(libraries, i); | |
470 ASSERT(!Dart_IsError(libraryIdHandle)); | |
471 Dart_Handle exception = 0; | |
472 int64_t int64LibraryId = DartUtilities::toInteger(libraryIdHandle, excep
tion); | |
473 ASSERT(!exception); | |
474 intptr_t libraryId = static_cast<intptr_t>(int64LibraryId); | |
475 ASSERT(libraryId == int64LibraryId); | |
476 | |
477 Dart_Handle libraryURL = Dart_GetLibraryURL(libraryId); | |
478 ASSERT(Dart_IsString(libraryURL)); | |
479 | |
480 Dart_SetLibraryDebuggable(libraryId, true); | |
481 | |
482 Dart_Handle scripts = Dart_GetScriptURLs(libraryURL); | |
483 ASSERT(Dart_IsList(scripts)); | |
484 | |
485 intptr_t scriptsLength = 0; | |
486 result = Dart_ListLength(scripts, &scriptsLength); | |
487 ASSERT(!Dart_IsError(result)); | |
488 for (intptr_t j = 0; j < scriptsLength; ++j) { | |
489 Dart_Handle scriptURL = Dart_ListGetAt(scripts, j); | |
490 ASSERT(Dart_IsString(scriptURL)); | |
491 | |
492 Dart_Handle source = Dart_ScriptGetSource(libraryId, scriptURL); | |
493 ASSERT(Dart_IsString(source)); | |
494 | |
495 v8::Handle<v8::Object> v8Script = v8::Object::New(v8Isolate); | |
496 v8Script->Set(v8::String::NewFromUtf8(v8Isolate, "libraryId"), v8::N
umber::New(v8Isolate, libraryId)); | |
497 v8Script->Set(v8::String::NewFromUtf8(v8Isolate, "scriptURL"), V8Con
verter::stringToV8(scriptURL)); | |
498 v8Script->Set(v8::String::NewFromUtf8(v8Isolate, "source"), V8Conver
ter::stringToV8(source)); | |
499 v8Script->Set(v8::String::NewFromUtf8(v8Isolate, "contextData"), con
textData); | |
500 | |
501 v8Scripts->Set(v8::Integer::New(v8Isolate, v8Scripts->Length()), v8S
cript); | |
502 } | |
503 } | |
504 v8SetReturnValue(args, v8Scripts); | |
505 } | |
506 | |
507 static void setBreakpoint(const v8::FunctionCallbackInfo<v8::Value>& args) | |
508 { | |
509 Dart_Isolate isolate = isolateMap().get(args[0]->Int32Value()); | |
510 | |
511 DartIsolateScope scope(isolate); | |
512 DartApiScope apiScope; | |
513 | |
514 Dart_Handle scriptURL = V8Converter::stringToDart(args[1]); | |
515 Dart_Handle breakpointId = Dart_SetBreakpoint(scriptURL, args[2]->Int32Value
()); | |
516 if (!Dart_IsError(breakpointId)) | |
517 v8SetReturnValue(args, V8Converter::numberToV8(breakpointId)); | |
518 } | |
519 | |
520 static void removeBreakpoint(const v8::FunctionCallbackInfo<v8::Value>& args) | |
521 { | |
522 Dart_Isolate isolate = isolateMap().get(args[0]->Int32Value()); | |
523 | |
524 DartIsolateScope scope(isolate); | |
525 DartApiScope apiScope; | |
526 Dart_Handle ALLOW_UNUSED result = Dart_RemoveBreakpoint(args[1]->Int32Value(
)); | |
527 ASSERT(!Dart_IsError(result)); | |
528 } | |
529 | |
530 static void getBreakpointLine(const v8::FunctionCallbackInfo<v8::Value>& args) | |
531 { | |
532 Dart_Isolate isolate = isolateMap().get(args[0]->Int32Value()); | |
533 | |
534 DartIsolateScope scope(isolate); | |
535 DartApiScope apiScope; | |
536 v8SetReturnValue(args, V8Converter::numberToV8(Dart_GetBreakpointLine(args[1
]->Int32Value()))); | |
537 } | |
538 | |
539 static void setExceptionPauseInfo(const v8::FunctionCallbackInfo<v8::Value>& arg
s) | |
540 { | |
541 Dart_Isolate isolate = isolateMap().get(args[0]->Int32Value()); | |
542 bool pauseOnAllExceptions = args[1]->BooleanValue(); | |
543 bool pauseOnUnhandledExceptions = args[2]->BooleanValue(); | |
544 | |
545 DartIsolateScope scope(isolate); | |
546 DartApiScope apiScope; | |
547 Dart_ExceptionPauseInfo pauseInfo = kNoPauseOnExceptions; | |
548 if (pauseOnUnhandledExceptions) | |
549 pauseInfo = kPauseOnUnhandledExceptions; | |
550 if (pauseOnAllExceptions) | |
551 pauseInfo = kPauseOnAllExceptions; | |
552 Dart_SetExceptionPauseInfo(pauseInfo); | |
553 } | |
554 | |
555 static void stepInto(const v8::FunctionCallbackInfo<v8::Value>& args) | |
556 { | |
557 Dart_SetStepInto(); | |
558 } | |
559 | |
560 static void stepOver(const v8::FunctionCallbackInfo<v8::Value>& args) | |
561 { | |
562 Dart_SetStepOver(); | |
563 } | |
564 | |
565 static void stepOut(const v8::FunctionCallbackInfo<v8::Value>& args) | |
566 { | |
567 Dart_SetStepOut(); | |
568 } | |
569 | |
570 static void evaluateInScope(const v8::FunctionCallbackInfo<v8::Value>& args) | |
571 { | |
572 v8::Handle<v8::String> expression = args[0]->ToString(); | |
573 v8::Handle<v8::Value> receiver = args[1]; | |
574 v8::Handle<v8::Object> functionProxy = args[2].As<v8::Object>(); | |
575 v8::Handle<v8::Value> localVariablesProxy = args[3]; | |
576 bool disableBreak = args[4]->BooleanValue(); | |
577 | |
578 DartScopes scopes(functionProxy, disableBreak); | |
579 Dart_Handle target = 0; | |
580 if (receiver->IsNull() || receiver->IsUndefined()) { | |
581 target = scopes.handle; | |
582 // Dart_EvaluateExpr cannot handle targets that are function handles so | |
583 // we walk up the chain of function owners until we reach a type | |
584 // or library handle. | |
585 while (Dart_IsFunction(target)) | |
586 target = Dart_FunctionOwner(target); | |
587 ASSERT(Dart_IsLibrary(target) || Dart_IsType(target)); | |
588 } else { | |
589 target = DartHandleProxy::unwrapValue(receiver); | |
590 } | |
591 | |
592 ASSERT(!Dart_IsError(target)); | |
593 Dart_Handle localVariables = DartHandleProxy::unwrapValue(localVariablesProx
y); | |
594 | |
595 v8SetReturnValue(args, DartHandleProxy::evaluate(target, V8Converter::string
ToDart(expression), localVariables)); | |
596 } | |
597 | |
598 void DartDebugServer::ensureHooksInstalled() | |
599 { | |
600 DEFINE_STATIC_LOCAL(bool, hooksInstalled, (false)); | |
601 | |
602 if (hooksInstalled) | |
603 return; | |
604 | |
605 hooksInstalled = true; | |
606 | |
607 ASSERT(Dart_CurrentIsolate()); | |
608 v8::HandleScope scope(v8::Isolate::GetCurrent()); | |
609 V8Scope v8Scope(0, v8::Debug::GetDebugContext()); | |
610 String dartDebugHooksSource(reinterpret_cast<const char*>(DartDebugHooksSour
ce_js), sizeof(DartDebugHooksSource_js)); | |
611 | |
612 v8::Isolate* v8Isolate = v8::Isolate::GetCurrent(); | |
613 m_dartDebugObject.set(v8Isolate, v8::Local<v8::Object>::Cast(v8::Script::Com
pile(v8String(v8Isolate, dartDebugHooksSource))->Run())); | |
614 | |
615 // We must set the v8 context to the page's context before invoking Dart | |
616 // code because of security checks in the console.log implementation | |
617 // (see InjectedScriptManager::canAccessInspectedWindow). | |
618 DartUtilities::currentV8Context()->Enter(); | |
619 v8::Local<v8::Object> evaluateInScopeFunction = v8::FunctionTemplate::New(v8
Isolate, &evaluateInScope)->GetFunction(); | |
620 DartUtilities::currentV8Context()->Exit(); | |
621 | |
622 v8::Local<v8::Object> nativeCallbacks = v8::Object::New(v8Isolate); | |
623 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "handleDebugEvent"),
v8::FunctionTemplate::New(v8Isolate, &handleDebugEvent)->GetFunction()); | |
624 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "scriptsForIsolate")
, v8::FunctionTemplate::New(v8Isolate, &scriptsForIsolate)->GetFunction()); | |
625 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "setBreakpoint"), v8
::FunctionTemplate::New(v8Isolate, &setBreakpoint)->GetFunction()); | |
626 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "removeBreakpoint"),
v8::FunctionTemplate::New(v8Isolate, &removeBreakpoint)->GetFunction()); | |
627 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "getBreakpointLine")
, v8::FunctionTemplate::New(v8Isolate, &getBreakpointLine)->GetFunction()); | |
628 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "setExceptionPauseIn
fo"), v8::FunctionTemplate::New(v8Isolate, &setExceptionPauseInfo)->GetFunction(
)); | |
629 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "stepInto"), v8::Fun
ctionTemplate::New(v8Isolate, &stepInto)->GetFunction()); | |
630 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "stepOver"), v8::Fun
ctionTemplate::New(v8Isolate, &stepOver)->GetFunction()); | |
631 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "stepOut"), v8::Func
tionTemplate::New(v8Isolate, &stepOut)->GetFunction()); | |
632 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "evaluateInScope"),
evaluateInScopeFunction); | |
633 { | |
634 // Trampoline script is required to properly set calling context before | |
635 // invoking Dart code because of security checks in console.log | |
636 // implementation (see InjectedScriptManager::canAccessInspectedWindow). | |
637 V8Scope v8scope(0); | |
638 v8::Handle<v8::String> trampolineScript = v8::String::NewFromUtf8(v8Isol
ate, "(function (func, args) { return func.apply(this, args); })"); | |
639 v8::Local<v8::Function> trampoline = v8::Local<v8::Function>::Cast(v8::S
cript::Compile(trampolineScript)->Run()); | |
640 nativeCallbacks->Set(v8::String::NewFromUtf8(v8Isolate, "invocationTramp
oline"), trampoline); | |
641 } | |
642 dartDebugObject()->Set(v8::String::NewFromUtf8(v8Isolate, "nativeCallbacks")
, nativeCallbacks); | |
643 } | |
644 | |
645 v8::Local<v8::Object> DartDebugServer::dartDebugObject() | |
646 { | |
647 return m_dartDebugObject.newLocal(v8::Isolate::GetCurrent()); | |
648 } | |
649 | |
650 } | |
OLD | NEW |