Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(430)

Side by Side Diff: Source/bindings/core/dart/DartScriptDebugServer.cpp

Issue 1532413002: Added Dartium changes onto 45.0.2454.104 (Closed) Base URL: http://src.chromium.org/blink/branches/chromium/2454
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2014 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/core/dart/DartScriptDebugServer.h"
32
33 #include "bindings/core/dart/DartApplicationLoader.h"
34 #include "bindings/core/dart/DartController.h"
35 #include "bindings/core/dart/DartScriptDebugListener.h"
36 #include "bindings/core/dart/DartUtilities.h"
37 #include "bindings/core/dart/V8Converter.h"
38 #include "bindings/core/v8/PageScriptDebugServer.h"
39 #include "bindings/core/v8/ScriptController.h"
40 #include "bindings/core/v8/V8Binding.h"
41 #include "bindings/core/v8/V8ScriptState.h"
42 #include "bindings/core/v8/WindowProxy.h"
43 #include "core/dom/Document.h"
44 #include "core/frame/LocalDOMWindow.h"
45 #include "core/inspector/InspectorController.h"
46 #include "core/inspector/InspectorDebuggerAgent.h"
47 #include "core/inspector/InspectorInstrumentation.h"
48 #include "core/inspector/InstrumentingAgents.h"
49 #include "core/inspector/JSONParser.h"
50 #include "core/page/Page.h"
51 #include "platform/JSONValues.h"
52 #include "platform/Logging.h"
53 #include "wtf/HashMap.h"
54 #include "wtf/MessageQueue.h"
55 #include "wtf/ThreadingPrimitives.h"
56 #include "wtf/Vector.h"
57
58 namespace blink {
59
60 void drainTaskQueue(MessageQueue<ScriptDebugServer::Task>& tasks)
61 {
62 OwnPtr<ScriptDebugServer::Task> currentMessage;
63 while ((currentMessage = tasks.tryGetMessage()))
64 currentMessage->run();
65 }
66
67 // Wrapper to let the V8 code to handle debug messages stay unchanged for now.
68 class DrainQueueTask : public ScriptDebugServer::Task {
69 public:
70 DrainQueueTask(MessageQueue<ScriptDebugServer::Task>* tasks) : m_tasks(tasks ) { }
71 virtual void run()
72 {
73 drainTaskQueue(*m_tasks);
74 }
75 private:
76 MessageQueue<ScriptDebugServer::Task>* m_tasks;
77 };
78
79 // Thread-safe helper class to track all current isolates.
80 class ThreadSafeIsolateTracker {
81 WTF_MAKE_NONCOPYABLE(ThreadSafeIsolateTracker);
82 public:
83 ThreadSafeIsolateTracker() { }
84
85 void add(Dart_Isolate isolate)
86 {
87 MutexLocker locker(m_mutex);
88 m_isolates.add(isolate);
89 }
90
91 void remove(Dart_Isolate isolate)
92 {
93 MutexLocker locker(m_mutex);
94 m_isolates.remove(isolate);
95 }
96
97 Vector<Dart_Isolate> isolates()
98 {
99 MutexLocker locker(m_mutex);
100 Vector<Dart_Isolate> result;
101 copyToVector(m_isolates, result);
102 return result;
103 }
104
105 private:
106 Mutex m_mutex;
107 HashSet<Dart_Isolate> m_isolates;
108 };
109
110 // Thread safe method to get a list of all running isolates.
111 static ThreadSafeIsolateTracker& threadSafeIsolateTracker()
112 {
113 AtomicallyInitializedStatic(ThreadSafeIsolateTracker&, tracker = *new Thread SafeIsolateTracker);
114 return tracker;
115 }
116
117 static MessageQueue<ScriptDebugServer::Task>& debugTaskQueue()
118 {
119 AtomicallyInitializedStatic(MessageQueue<ScriptDebugServer::Task>&, tasks = *new MessageQueue<ScriptDebugServer::Task>);
120 return tasks;
121 }
122
123 static Dart_ExceptionPauseInfo calculatePauseInfo(ScriptDebugServer::PauseOnExce ptionsState pauseOnExceptionState)
124 {
125 switch (pauseOnExceptionState) {
126 case ScriptDebugServer::DontPauseOnExceptions:
127 return kNoPauseOnExceptions;
128 case ScriptDebugServer::PauseOnAllExceptions:
129 return kPauseOnAllExceptions;
130 case ScriptDebugServer::PauseOnUncaughtExceptions:
131 return kPauseOnUnhandledExceptions;
132 }
133 return kNoPauseOnExceptions;
134 }
135
136 DartBreakpoint::DartBreakpoint(intptr_t breakpointId, Dart_Isolate isolate)
137 : m_breakpointId(breakpointId)
138 , m_isolate(isolate)
139 {
140 }
141
142 DartBreakpointInfo::DartBreakpointInfo(const String& scriptUrl, const ScriptBrea kpoint& scriptBreakpoint)
143 : m_scriptUrl(scriptUrl)
144 , m_scriptBreakpoint(scriptBreakpoint)
145 {
146 }
147
148 DartPageDebug::DartPageDebug(Page* page, int pageId)
149 : m_page(page)
150 , m_listener(0)
151 , m_pageId(pageId)
152 , m_nextBreakpointId(1)
153 , m_nextScriptId(1)
154 {
155 }
156
157 DartPageDebug::~DartPageDebug()
158 {
159 for (BreakpointMap::iterator it = m_breakpoints.begin(); it != m_breakpoints .end(); ++it)
160 delete it->value;
161
162 for (SetBreakpointsForIsolateMap::iterator it = m_setBreakpointsForIsolate.b egin(); it != m_setBreakpointsForIsolate.end(); ++it)
163 delete it->value;
164 }
165
166 void DartPageDebug::registerIsolate(Dart_Isolate isolate)
167 {
168 m_isolateMap.add(isolate);
169 }
170
171 intptr_t DartPageDebug::setBreakpointHelper(DartBreakpointInfo* breakpointInfo, const String& breakpointIdString, Dart_Isolate isolate, Dart_Handle& exception)
172 {
173 SetBreakpointsMap* setBreakpoints = getSetBreakpoints(isolate);
174 SetBreakpointsMap::iterator it = setBreakpoints->find(breakpointIdString);
175 if (it != setBreakpoints->end())
176 return it->value;
177 Dart_Handle scriptURL = DartUtilities::convertSourceString(breakpointInfo->m _scriptUrl);
178 // FIXME: use scriptBreakpoint.columnNumber and ScriptBreakpoint.condition a s well.
179 Dart_Handle ret = Dart_SetBreakpoint(scriptURL, breakpointInfo->m_scriptBrea kpoint.lineNumber + 1);
180 if (Dart_IsError(ret)) {
181 exception = ret;
182 return ILLEGAL_BREAKPOINT_ID;
183 }
184 ASSERT(Dart_IsInteger(ret));
185 intptr_t breakpointId = DartUtilities::dartToInt(ret, exception);
186 ASSERT(!exception);
187 if (exception) {
188 return ILLEGAL_BREAKPOINT_ID;
189 }
190 setBreakpoints->add(breakpointIdString, breakpointId);
191 m_breakpointIdMap.set(breakpointId, breakpointIdString);
192 breakpointInfo->m_breakpoints.append(DartBreakpoint(breakpointId, isolate));
193 return breakpointId;
194 }
195
196 String DartPageDebug::setBreakpoint(const String& sourceID, const ScriptBreakpoi nt& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber, bool inter statementLocation)
197 {
198 String breakpointIdString = String::format("{\"dartBreakpoint\":%d,\"page\": %d}", m_nextBreakpointId, m_pageId);
199 *actualLineNumber = scriptBreakpoint.lineNumber;
200 *actualColumnNumber = scriptBreakpoint.columnNumber;
201 m_nextBreakpointId++;
202 if (!m_idToScriptUrlMap.contains(sourceID)) {
203 return "Unable to set breakpoint. Unknown sourceID";
204 }
205 Vector<Dart_Isolate> isolates;
206 m_isolateMap.copyValues(isolates);
207 for (Vector<Dart_Isolate>::iterator it = isolates.begin(); it != isolates.en d(); ++it) {
208 Dart_Isolate isolate = *it;
209 DartIsolateScope scope(isolate);
210 DartApiScope apiScope;
211 Dart_Handle exception = 0;
212 if (!DartDOMData::current()->applicationLoader()->running()) {
213 // Skip until the loader is actually running. We'll set the breakpoi nt at that point.
214 break;
215 }
216 DartBreakpointInfo* breakpointInfo;
217 BreakpointMap::iterator breakpointIt = m_breakpoints.find(breakpointIdSt ring);
218 if (breakpointIt != m_breakpoints.end()) {
219 breakpointInfo = breakpointIt->value;
220 } else {
221 breakpointInfo = new DartBreakpointInfo(m_idToScriptUrlMap.get(sourc eID), scriptBreakpoint);
222 m_breakpoints.set(breakpointIdString, breakpointInfo);
223 }
224
225 intptr_t breakpointId = setBreakpointHelper(breakpointInfo, breakpointId String, isolate, exception);
226 if (exception)
227 continue;
228
229 if (breakpointId != ILLEGAL_BREAKPOINT_ID) {
230 Dart_Handle breakpointLine = Dart_GetBreakpointLine(breakpointId);
231 if (!Dart_IsError(breakpointLine)) {
232 ASSERT(Dart_IsInteger(breakpointLine));
233 *actualLineNumber = DartUtilities::dartToInt(breakpointLine, exc eption) - 1;
234 ASSERT(!exception);
235 }
236 }
237 }
238 return breakpointIdString;
239 }
240
241
242 void DartPageDebug::removeBreakpointHelper(DartBreakpointInfo* breakpointInfo)
243 {
244 Vector<DartBreakpoint>& breakpoints = breakpointInfo->m_breakpoints;
245 for (Vector<DartBreakpoint>::iterator it = breakpoints.begin(); it != breakp oints.end(); ++it) {
246 DartBreakpoint& breakpoint = *it;
247 DartIsolateScope scope(breakpoint.m_isolate);
248 DartApiScope apiScope;
249 // perhaps this isn't needed if the isolate will be removed soon anyway.
250 Dart_Handle ALLOW_UNUSED ret = Dart_RemoveBreakpoint(breakpoint.m_breakp ointId);
251 ASSERT(Dart_IsBoolean(ret));
252 Dart_Handle ALLOW_UNUSED exception = 0;
253 ASSERT(DartUtilities::dartToBool(ret, exception));
254 ASSERT(!exception);
255 }
256 delete breakpointInfo;
257 }
258
259 void DartPageDebug::removeBreakpoint(const String& breakpointId)
260 {
261 if (m_breakpoints.contains(breakpointId)) {
262 removeBreakpointHelper(m_breakpoints.get(breakpointId));
263 m_breakpoints.remove(breakpointId);
264 }
265 }
266
267 void DartPageDebug::clearBreakpointsForIsolate(Dart_Isolate isolate)
268 {
269 // Warning: this code is O(num_isolates * num_breakpoints)
270 for (BreakpointMap::iterator i = m_breakpoints.begin(); i != m_breakpoints.e nd(); ++i) {
271 Vector<DartBreakpoint>& breakpoints = i->value->m_breakpoints;
272 for (size_t j = 0; j < breakpoints.size(); j++) {
273 DartBreakpoint& breakpoint = breakpoints[j];
274 if (breakpoint.m_isolate == isolate) {
275 // No need to actually call Dart_RemoveBreakpoint as the
276 // isolate is about to be shut down.
277 breakpoints.remove(j);
278 break;
279 }
280 }
281 }
282 }
283
284 void DartPageDebug::dispatchDidParseSource(intptr_t libraryId, Dart_Handle scrip tURL, Dart_Isolate isolate)
285 {
286 ASSERT(Dart_IsString(scriptURL));
287 DartScriptDebugListener::Script script;
288 script.url = DartUtilities::toString(scriptURL);
289 String sourceID = getScriptId(script.url);
290 Dart_Handle scriptSource = Dart_ScriptGetSource(libraryId, scriptURL);
291 if (Dart_IsString(scriptSource)) {
292 script.source = DartUtilities::toString(scriptSource);
293 } else {
294 // FIXME: this is a bit ugly.
295 script.source = "ERROR: unable to get source";
296 }
297 // FIXME: track script.sourceMappingURL for dart-dart source map support.
298
299 Dart_Handle info = Dart_ScriptGetTokenInfo(libraryId, scriptURL);
300 ASSERT(Dart_IsList(info));
301 intptr_t infoLength = 0;
302 Dart_Handle ALLOW_UNUSED result = Dart_ListLength(info, &infoLength);
303 ASSERT(!Dart_IsError(result));
304 Dart_Handle elem;
305 int lastLineNumber = 0;
306 int lastColumnNumber = 0;
307 intptr_t lastLineStart = 0;
308 for (intptr_t i = infoLength - 3; i >= 0; i--) {
309 elem = Dart_ListGetAt(info, i);
310 if (Dart_IsNull(elem)) {
311 lastLineStart = i;
312 break;
313 }
314 }
315 Dart_Handle exception = 0;
316 lastLineNumber = DartUtilities::toInteger(Dart_ListGetAt(info, lastLineStart + 1), exception);
317 ASSERT(!exception);
318 lastColumnNumber = DartUtilities::toInteger(Dart_ListGetAt(info, infoLength - 1), exception);
319 ASSERT(!exception);
320
321 script.startLine = 0;
322 script.startColumn = 0;
323 script.endLine = lastLineNumber + 1;
324 script.endColumn = !lastLineNumber ? lastColumnNumber : 0;
325 script.isContentScript = false;
326 script.language = String("Dart");
327 script.libraryId = libraryId;
328 m_listener->didParseSource(sourceID, script, CompileResult::CompileSuccess);
329 }
330
331 String DartPageDebug::getScriptId(const String& url)
332 {
333 HashMap<String, String>::iterator it = m_scriptUrlToIdMap.find(url);
334 if (it == m_scriptUrlToIdMap.end()) {
335 String id = String::format("{\"dartScript\":%d,\"page\":%d}", m_nextScri ptId, m_pageId);
336 m_nextScriptId++;
337 m_scriptUrlToIdMap.set(url, id);
338 m_idToScriptUrlMap.set(id, url);
339 return id;
340 }
341 return it->value;
342 }
343
344 void DartPageDebug::clearBreakpoints()
345 {
346 for (BreakpointMap::iterator i = m_breakpoints.begin(); i != m_breakpoints.e nd(); ++i)
347 removeBreakpointHelper(i->value);
348 m_breakpoints.clear();
349 m_breakpointIdMap.clear();
350 }
351
352 void DartPageDebug::registerIsolateScripts(Dart_Isolate isolate)
353 {
354 Dart_Handle libraries = Dart_GetLibraryIds();
355 ASSERT(Dart_IsList(libraries));
356
357 intptr_t librariesLength = 0;
358 Dart_Handle ALLOW_UNUSED result = Dart_ListLength(libraries, &librariesLengt h);
359 ASSERT(!Dart_IsError(result));
360 for (intptr_t i = 0; i < librariesLength; ++i) {
361 Dart_Handle libraryIdHandle = Dart_ListGetAt(libraries, i);
362 ASSERT(!Dart_IsError(libraryIdHandle));
363 Dart_Handle exception = 0;
364 int64_t int64LibraryId = DartUtilities::toInteger(libraryIdHandle, excep tion);
365 ASSERT(!exception);
366 intptr_t libraryId = static_cast<intptr_t>(int64LibraryId);
367 ASSERT(libraryId == int64LibraryId);
368
369 Dart_Handle libraryURL = Dart_GetLibraryURL(libraryId);
370 ASSERT(Dart_IsString(libraryURL));
371
372 // FIXMEDART: we may be doing this more than once per library.
373 Dart_SetLibraryDebuggable(libraryId, true);
374
375 Dart_Handle scripts = Dart_GetScriptURLs(libraryURL);
376 ASSERT(Dart_IsList(scripts));
377
378 intptr_t scriptsLength = 0;
379 result = Dart_ListLength(scripts, &scriptsLength);
380 ASSERT(!Dart_IsError(result));
381 for (intptr_t j = 0; j < scriptsLength; ++j) {
382 Dart_Handle scriptURL = Dart_ListGetAt(scripts, j);
383 dispatchDidParseSource(libraryId, scriptURL, isolate);
384 }
385 }
386 }
387
388 Vector<Dart_Isolate> DartPageDebug::isolates()
389 {
390 Vector<Dart_Isolate> result;
391 m_isolateMap.copyValues(result);
392 return result;
393 }
394
395 void DartPageDebug::addListener(DartScriptDebugListener* listener)
396 {
397 ASSERT(!m_listener);
398 m_listener = listener;
399
400 Vector<Dart_Isolate> iter = isolates();
401 for (Vector<Dart_Isolate>::iterator i = iter.begin(); i != iter.end(); ++i) {
402 Dart_Isolate isolate = *i;
403 DartIsolateScope scope(isolate);
404 DartApiScope apiScope;
405 isolateLoaded();
406 }
407 }
408
409 void DartPageDebug::removeListener()
410 {
411 m_listener = 0;
412 Vector<Dart_Isolate> iter = isolates();
413 for (Vector<Dart_Isolate>::iterator i = iter.begin(); i != iter.end(); ++i) {
414 Dart_Isolate isolate = *i;
415 DartIsolateScope scope(isolate);
416 DartApiScope apiScope;
417 Dart_SetPausedEventHandler(0);
418 Dart_SetExceptionThrownHandler(0);
419 Dart_SetIsolateEventHandler(0);
420 Dart_SetExceptionPauseInfo(kNoPauseOnExceptions);
421 }
422 // FIXME: Remove all breakpoints set by the agent. JavaScript does not
423 // remove the breakpoints either.
424 }
425
426 void DartPageDebug::unregisterIsolate(Dart_Isolate isolate)
427 {
428 clearBreakpointsForIsolate(isolate);
429 m_isolateMap.removeByValue(isolate);
430 SetBreakpointsForIsolateMap::iterator it = m_setBreakpointsForIsolate.find(i solate);
431 if (it != m_setBreakpointsForIsolate.end()) {
432 m_setBreakpointsForIsolate.remove(it);
433 }
434 }
435
436 void DartPageDebug::isolateLoaded()
437 {
438 if (!m_listener)
439 return;
440
441 Dart_Isolate isolate = Dart_CurrentIsolate();
442 Dart_SetPausedEventHandler(DartScriptDebugServer::pausedEventHandler);
443 Dart_SetExceptionThrownHandler(DartScriptDebugServer::exceptionHandler);
444 Dart_SetIsolateEventHandler(DartScriptDebugServer::isolateEventHandler);
445
446 Dart_ExceptionPauseInfo pauseInfo = calculatePauseInfo(
447 DartScriptDebugServer::shared().pauseOnExceptionState());
448 Dart_SetExceptionPauseInfo(pauseInfo);
449
450 ASSERT(isolate);
451
452 V8Scope v8Scope(DartDOMData::current());
453
454 LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame();
455 DartController* controller = DartController::retrieve(frame);
456 Vector<DartScriptState*> scriptStates;
457 controller->collectScriptStatesForIsolate(isolate, DartUtilities::currentV8C ontext(), scriptStates);
458 for (size_t i = 0; i< scriptStates.size(); i++)
459 InspectorInstrumentation::didCreateIsolatedContext(frame, scriptStates[i ], 0);
460
461 registerIsolateScripts(isolate);
462
463
464 for (BreakpointMap::iterator it = m_breakpoints.begin(); it != m_breakpoints .end(); ++it) {
465 Dart_Handle ALLOW_UNUSED exception = 0;
466 setBreakpointHelper(it->value, it->key, isolate, exception);
467 }
468 }
469
470 SetBreakpointsMap* DartPageDebug::getSetBreakpoints(Dart_Isolate isolate)
471 {
472 SetBreakpointsForIsolateMap::iterator it = m_setBreakpointsForIsolate.find(i solate);
473 if (it == m_setBreakpointsForIsolate.end()) {
474 SetBreakpointsMap* map = new SetBreakpointsMap();
475 m_setBreakpointsForIsolate.add(isolate, map);
476 return map;
477 }
478 return it->value;
479 }
480
481 void DartPageDebug::deferredReady()
482 {
483 Dart_Isolate isolate = Dart_CurrentIsolate();
484
485 ASSERT(isolate);
486
487 V8Scope v8Scope(DartDOMData::current());
488
489 LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame();
490 DartController* controller = DartController::retrieve(frame);
491 Vector<DartScriptState*> scriptStates;
492 controller->collectScriptStatesForIsolate(isolate, DartUtilities::currentV8C ontext(), scriptStates);
493 // FIXME: only call for newly created script states to improve performance.
494 for (size_t i = 0; i < scriptStates.size(); i++)
495 InspectorInstrumentation::didCreateIsolatedContext(frame, scriptStates[i ], 0);
496
497 registerIsolateScripts(isolate);
498
499 for (BreakpointMap::iterator it = m_breakpoints.begin(); it != m_breakpoints .end(); ++it) {
500 Dart_Handle ALLOW_UNUSED exception = 0;
501 setBreakpointHelper(it->value, it->key, isolate, exception);
502 }
503 }
504
505 String DartPageDebug::lookupBreakpointId(intptr_t dartBreakpointId)
506 {
507 if (dartBreakpointId != ILLEGAL_BREAKPOINT_ID) {
508 BreakpointIdMap::iterator it = m_breakpointIdMap.find(dartBreakpointId);
509 if (it != m_breakpointIdMap.end())
510 return it->value;
511 }
512 return "";
513 }
514
515 DartScriptDebugServer::DartScriptDebugServer()
516 : m_pauseOnExceptionState(ScriptDebugServer::DontPauseOnExceptions)
517 , m_breakpointsActivated(true)
518 , m_runningNestedMessageLoop(false)
519 , m_executionState(0)
520 , m_pausedIsolate(0)
521 , m_pausedPage(0)
522 , m_clientMessageLoop(0)
523 , m_nextPageId(1)
524 {
525 }
526
527 DartScriptDebugServer::~DartScriptDebugServer()
528 {
529 for (DebugDataMap::iterator it = m_pageIdToDebugDataMap.begin(); it != m_pag eIdToDebugDataMap.end(); ++it)
530 delete it->value;
531 }
532
533 DartPageDebug* DartScriptDebugServer::lookupPageDebugForId(const String& id)
534 {
535 RefPtr<JSONValue> json = parseJSON(id);
536 ASSERT(json && json->type() == JSONValue::TypeObject);
537 if (json && json->type() == JSONValue::TypeObject) {
538 size_t pageId;
539 bool success = json->asObject()->getNumber("page", &pageId);
540 ASSERT(success);
541 if (success)
542 return m_pageIdToDebugDataMap.get(pageId);
543 }
544 return 0;
545 }
546
547 DartPageDebug* DartScriptDebugServer::lookupPageDebug(Page* page)
548 {
549 ASSERT(page);
550 PageToIdMap::iterator it = m_pageToIdMap.find(page);
551 if (it != m_pageToIdMap.end())
552 return m_pageIdToDebugDataMap.get(it->value);
553
554 size_t pageId = m_nextPageId++;
555 m_pageToIdMap.set(page, pageId);
556 DartPageDebug* pageDebug = new DartPageDebug(page, pageId);
557 m_pageIdToDebugDataMap.set(pageId, pageDebug);
558 return pageDebug;
559 }
560
561 void DartScriptDebugServer::clearWindowShell(Page* page)
562 {
563 // FIXME: find a cleaner long term solution than just ignoring
564 // clearWindowShell requests where we were unable to determine the Page
565 // likely because the Page is already being destroyed. One strategy would
566 // be to switch all references to Page to reference LocalFrame.
567 if (!page)
568 return;
569 PageToIdMap::iterator it = m_pageToIdMap.find(page);
570 if (it != m_pageToIdMap.end()) {
571 size_t pageId = it->value;
572 DartPageDebug* pageDebug = m_pageIdToDebugDataMap.get(pageId);
573 // Only clear the page if all isolates on the page have shutdown.
574 if (pageDebug->isolates().isEmpty()) {
575 pageDebug->clearBreakpoints();
576 }
577 }
578 }
579
580 String DartScriptDebugServer::getScriptId(const String& url, Dart_Isolate isolat e)
581 {
582 // FIXME: this is a ugly. It would be better to get the domData for the
583 // specified isolate.
584 ASSERT(isolate == Dart_CurrentIsolate());
585 DartPageDebug* pageDebug = lookupPageDebug(DartUtilities::domWindowForCurren tIsolate()->document()->page());
586 ASSERT(pageDebug);
587 if (!pageDebug)
588 return "";
589 return pageDebug->getScriptId(url);
590 }
591
592 void DartScriptDebugServer::registerIsolate(Dart_Isolate isolate, Page* page)
593 {
594 threadSafeIsolateTracker().add(isolate);
595
596 DartIsolateScope scope(isolate);
597 DartApiScope apiScope;
598
599 DartPageDebug* pageDebug = lookupPageDebug(page);
600 pageDebug->registerIsolate(isolate);
601
602 }
603
604 // FIXMEDART: we aren't really handling adding and removing breakpoints
605 // as new isolates add/remove themselves.
606 String DartScriptDebugServer::setBreakpoint(const String& sourceID, const Script Breakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber, bo ol interstatementLocation)
607 {
608 DartPageDebug* pageDebug = lookupPageDebugForId(sourceID);
609 ASSERT(pageDebug);
610 if (!pageDebug)
611 return "";
612 return pageDebug->setBreakpoint(sourceID, scriptBreakpoint, actualLineNumber , actualColumnNumber, interstatementLocation);
613 }
614
615 void DartScriptDebugServer::removeBreakpoint(const String& breakpointId)
616 {
617 DartPageDebug* pageDebug = lookupPageDebugForId(breakpointId);
618 if (pageDebug) {
619 pageDebug->removeBreakpoint(breakpointId);
620 }
621 }
622
623 void DartScriptDebugServer::clearBreakpoints()
624 {
625 Vector<DartPageDebug*> list = pages();
626 for (Vector<DartPageDebug*>::iterator it = list.begin(); it != list.end(); + +it)
627 (*it)->clearBreakpoints();
628 }
629
630 void DartScriptDebugServer::setBreakpointsActivated(bool activated)
631 {
632 m_breakpointsActivated = activated;
633 }
634
635 ScriptDebugServer::PauseOnExceptionsState DartScriptDebugServer::pauseOnExceptio nsState()
636 {
637 return m_pauseOnExceptionState;
638 }
639
640 void DartScriptDebugServer::setPauseOnExceptionsState(ScriptDebugServer::PauseOn ExceptionsState pauseOnExceptionState)
641 {
642 if (m_pauseOnExceptionState == pauseOnExceptionState)
643 return;
644 m_pauseOnExceptionState = pauseOnExceptionState;
645
646 Dart_ExceptionPauseInfo pauseInfo = calculatePauseInfo(pauseOnExceptionState );
647
648 Vector<Dart_Isolate> iter = isolates();
649 for (Vector<Dart_Isolate>::iterator it = iter.begin(); it != iter.end(); ++i t) {
650 DartIsolateScope scope(*it);
651 DartApiScope apiScope;
652 Dart_SetExceptionPauseInfo(pauseInfo);
653 }
654 }
655
656 void DartScriptDebugServer::setPauseOnNextStatement(bool pause)
657 {
658 if (isPaused())
659 return;
660 if (pause) {
661 debugBreak();
662 } else {
663 cancelDebugBreak();
664 }
665 }
666
667 bool DartScriptDebugServer::canBreakProgram()
668 {
669 if (!m_breakpointsActivated)
670 return false;
671
672 // FIXME: what is the dart equivalent of
673 // v8::HandleScope scope(m_isolate);
674 // return !m_isolate->GetCurrentContext().IsEmpty();
675 // ?
676 return true;
677 }
678
679 void DartScriptDebugServer::breakProgram()
680 {
681 if (!canBreakProgram())
682 return;
683
684 // FIXME: determine if this method needs to be implemented for Dart.
685 }
686
687 void DartScriptDebugServer::continueProgram()
688 {
689 if (isPaused())
690 quitMessageLoopOnPause();
691 m_executionState = 0;
692 m_pausedIsolate = 0;
693 }
694
695 void DartScriptDebugServer::stepIntoStatement()
696 {
697 ASSERT(isPaused());
698 Dart_SetStepInto();
699 continueProgram();
700 }
701
702 void DartScriptDebugServer::stepOverStatement()
703 {
704 ASSERT(isPaused());
705 Dart_SetStepOver();
706 continueProgram();
707 }
708
709 void DartScriptDebugServer::stepOutOfFunction()
710 {
711 ASSERT(isPaused());
712 Dart_SetStepOut();
713 continueProgram();
714 }
715
716 bool DartScriptDebugServer::setScriptSource(const String& sourceID, const String & newContent, bool preview, String* error, RefPtr<TypeBuilder::Debugger::SetScri ptSourceError>& errorData, Dart_StackTrace newCallFrames, RefPtr<JSONObject>* re sult)
717 {
718 *error = "Dart does not support live editing source code yet.";
719 return false;
720 }
721
722 bool DartScriptDebugServer::executeSkipPauseRequest(DartScriptDebugListener::Ski pPauseRequest request, Dart_StackTrace stackTrace)
723 {
724 switch (request) {
725 case DartScriptDebugListener::NoSkip:
726 return false;
727 case DartScriptDebugListener::Continue:
728 return true;
729 case DartScriptDebugListener::StepInto:
730 case DartScriptDebugListener::StepOut:
731 break;
732 }
733 ASSERT(0);
734 // FIXMEDART: actually do something jacobr JACOBR
735 return true;
736 }
737
738 int DartScriptDebugServer::frameCount()
739 {
740 ASSERT(isPaused());
741 intptr_t length = 0;
742 Dart_StackTraceLength(m_executionState, &length);
743 return length;
744 }
745
746 Dart_StackTrace DartScriptDebugServer::currentCallFrames()
747 {
748 return m_executionState;
749 }
750
751 ScriptCallFrame DartScriptDebugServer::callFrameNoScopes(int index)
752 {
753 if (!isPaused())
754 return ScriptCallFrame();
755 DartIsolateScope scope(m_pausedIsolate);
756 DartApiScope apiScope;
757 return getScriptCallFrameHelper(index);
758 }
759
760 bool DartScriptDebugServer::isPaused()
761 {
762 return !!m_executionState;
763 }
764
765 DartScriptDebugServer& DartScriptDebugServer::shared()
766 {
767 DEFINE_STATIC_LOCAL(DartScriptDebugServer, server, ());
768 return server;
769 }
770
771 void DartScriptDebugServer::addListener(DartScriptDebugListener* listener, Page* page)
772 {
773 ScriptController& scriptController = page->deprecatedLocalMainFrame()->scrip t();
774 if (!scriptController.canExecuteScripts(NotAboutToExecuteScript))
775 return;
776
777 DartPageDebug* pageDebug = lookupPageDebug(page);
778 pageDebug->addListener(listener);
779 }
780
781 Vector<DartPageDebug*> DartScriptDebugServer::pages()
782 {
783 Vector<DartPageDebug*> result;
784 copyValuesToVector(m_pageIdToDebugDataMap, result);
785 return result;
786 }
787
788 Vector<Dart_Isolate> DartScriptDebugServer::isolates()
789 {
790 Vector<Dart_Isolate> result;
791 Vector<DartPageDebug*> allPages = pages();
792 for (Vector<DartPageDebug*>::iterator it = allPages.begin(); it != allPages. end(); ++it) {
793 Vector<Dart_Isolate> forPage = (*it)->isolates();
794 result.appendRange(forPage.begin(), forPage.end());
795 }
796 return result;
797 }
798
799 bool DartScriptDebugServer::resolveCodeLocation(const Dart_CodeLocation& locatio n, int* line, int* column)
800 {
801 // FIXME: cache the results of calling Dart_ScriptGetTokenInfo to improve
802 // performance.
803 Dart_Handle info = Dart_ScriptGetTokenInfo(location.library_id, location.scr ipt_url);
804 if (!Dart_IsList(info)) {
805 // FIXME: why does this sometimes happen?
806 return false;
807 }
808 intptr_t infoLength = 0;
809 Dart_Handle ALLOW_UNUSED result = Dart_ListLength(info, &infoLength);
810 ASSERT(!Dart_IsError(result));
811 Dart_Handle elem;
812 bool lineStart = true;
813 int currentLineNumber = 0;
814 for (intptr_t i = 0; i < infoLength; i++) {
815 elem = Dart_ListGetAt(info, i);
816 if (Dart_IsNull(elem)) {
817 lineStart = true;
818 } else {
819 ASSERT(Dart_IsInteger(elem));
820 Dart_Handle exception = 0;
821 int64_t value = DartUtilities::toInteger(elem, exception);
822 ASSERT(!exception);
823 if (lineStart) {
824 // Line number.
825 currentLineNumber = value;
826 lineStart = false;
827 } else {
828 // Token offset.
829 if (value == location.token_pos) {
830 *line = currentLineNumber;
831 ASSERT(i + 1 < infoLength);
832 *column = DartUtilities::toInteger(Dart_ListGetAt(info, i + 1), exception);
833 ASSERT(!exception);
834 return true;
835 }
836 i++; // skip columnNumber.
837 }
838 }
839 }
840 return false;
841 }
842
843 void DartScriptDebugServer::removeListener(DartScriptDebugListener* listener, Pa ge* page)
844 {
845 if (!m_pageToIdMap.contains(page))
846 return;
847
848 if (m_pausedPage == page)
849 continueProgram();
850
851 DartPageDebug* pageDebug = lookupPageDebug(page);
852 if (pageDebug)
853 pageDebug->removeListener();
854 }
855
856 void DartScriptDebugServer::setClientMessageLoop(PageScriptDebugServer::ClientMe ssageLoop* clientMessageLoop)
857 {
858 m_clientMessageLoop = clientMessageLoop;
859 }
860
861 void DartScriptDebugServer::runMessageLoopOnPause(Dart_Isolate isolate)
862 {
863 LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame();
864 m_pausedPage = frame->page();
865
866 // Wait for continue or step command.
867 m_clientMessageLoop->run(m_pausedPage);
868
869 DartPageDebug* pageDebug = lookupPageDebug(m_pausedPage);
870 // The listener may have been removed in the nested loop.
871 if (pageDebug && pageDebug->listener())
872 pageDebug->listener()->didContinue();
873
874 m_pausedPage = 0;
875 }
876
877 void DartScriptDebugServer::quitMessageLoopOnPause()
878 {
879 m_clientMessageLoop->quitNow();
880 }
881
882 void DartScriptDebugServer::interruptAndRunAllTasks()
883 {
884 Vector<Dart_Isolate> isolates = threadSafeIsolateTracker().isolates();
885 for (Vector<Dart_Isolate>::iterator it = isolates.begin(); it != isolates.en d(); ++it)
886 Dart_InterruptIsolate(*it);
887 }
888
889 void DartScriptDebugServer::runPendingTasks()
890 {
891 drainTaskQueue(debugTaskQueue());
892 }
893
894 void DartScriptDebugServer::debugBreak()
895 {
896 Vector<Dart_Isolate> iter = isolates();
897 for (Vector<Dart_Isolate>::iterator it = iter.begin(); it != iter.end(); ++i t) {
898 Dart_Isolate isolate = *it;
899 if (!m_interruptCalled.contains(isolate)) {
900 m_interruptCalled.add(isolate);
901 Dart_InterruptIsolate(isolate);
902 }
903 m_interruptCancelled.remove(isolate);
904 }
905 }
906
907 void DartScriptDebugServer::cancelDebugBreak()
908 {
909 // FIXME: it would be nice if the DartVM provided an API to directly cancel
910 // a debug break call like V8 does.
911 for (HashSet<Dart_Isolate>::iterator it = m_interruptCalled.begin(); it != m _interruptCalled.end(); ++it) {
912 m_interruptCancelled.add(*it);
913 }
914 }
915
916 Page* DartScriptDebugServer::inferPage(Dart_Isolate isolate)
917 {
918 for (DebugDataMap::iterator it = m_pageIdToDebugDataMap.begin(); it != m_pag eIdToDebugDataMap.end(); ++it) {
919 DartPageDebug* pageDebug = it->value;
920 if (pageDebug->containsIsolate(isolate)) {
921 return pageDebug->page();
922 }
923 }
924 return 0;
925 }
926
927 void DartScriptDebugServer::unregisterIsolate(Dart_Isolate isolate, Page* page)
928 {
929 threadSafeIsolateTracker().remove(isolate);
930
931 m_interruptCalled.remove(isolate);
932 m_interruptCancelled.remove(isolate);
933 if (!page) {
934 // FIXME: We should instead fix the underlying issue where the
935 // reference to the page is lost before we call unregisterIsolate in
936 // some cases.
937 page = inferPage(isolate);
938 ASSERT(page);
939 }
940 DartPageDebug* pageDebug = lookupPageDebug(page);
941 ASSERT(pageDebug);
942 if (pageDebug)
943 pageDebug->unregisterIsolate(isolate);
944 }
945
946 void DartScriptDebugServer::isolateLoaded()
947 {
948 Page* page = DartUtilities::domWindowForCurrentIsolate()->document()->page() ;
949 if (!page || !instrumentationForPage(page)->inspectorDebuggerAgent())
950 return;
951
952 DartPageDebug* pageDebug = lookupPageDebug(page);
953 if (!pageDebug)
954 return;
955
956 pageDebug->isolateLoaded();
957 }
958
959 void DartScriptDebugServer::deferredReady()
960 {
961 Page* page = DartUtilities::domWindowForCurrentIsolate()->document()->page() ;
962 if (!page || !instrumentationForPage(page)->inspectorDebuggerAgent())
963 return;
964
965 DartPageDebug* pageDebug = lookupPageDebug(page);
966 if (!pageDebug)
967 return;
968
969 pageDebug->deferredReady();
970 }
971
972 bool DartScriptDebugServer::isAnyScriptPaused()
973 {
974 return isPaused() || PageScriptDebugServer::shared().isPaused();
975 }
976
977 void DartScriptDebugServer::handleDartDebugEvent(Dart_IsolateId isolateId, intpt r_t breakpointId, Dart_Handle exception, const Dart_CodeLocation& location)
978 {
979 // Don't allow nested breaks.
980 if (isAnyScriptPaused())
981 return;
982
983 if (!m_breakpointsActivated && breakpointId != ILLEGAL_BREAKPOINT_ID)
984 return;
985
986 Dart_Isolate isolate = Dart_GetIsolate(isolateId);
987 ASSERT(isolate);
988 Dart_StackTrace stackTrace = 0;
989 Dart_Handle ALLOW_UNUSED result = Dart_GetStackTrace(&stackTrace);
990 ASSERT(!Dart_IsError(result));
991 result = 0;
992 DartPageDebug* pageDebug = lookupPageDebugForCurrentIsolate();
993 if (!pageDebug)
994 return;
995 DartScriptDebugListener* listener = pageDebug->listener();
996 if (listener) {
997 DartIsolateScope scope(isolate);
998 DartApiScope apiScope;
999 handleProgramBreak(isolate, stackTrace, breakpointId, exception, locatio n);
1000 }
1001 }
1002
1003 DartPageDebug* DartScriptDebugServer::lookupPageDebugForCurrentIsolate()
1004 {
1005 Page* page = DartUtilities::domWindowForCurrentIsolate()->document()->page() ;
1006 return lookupPageDebug(page);
1007 }
1008
1009 void DartScriptDebugServer::handleProgramBreak(Dart_Isolate isolate, Dart_StackT race stackTrace, intptr_t dartBreakpointId, Dart_Handle exception, const Dart_Co deLocation& location)
1010 {
1011 ASSERT(isolate == Dart_CurrentIsolate());
1012 // Don't allow nested breaks.
1013 if (isAnyScriptPaused())
1014 return;
1015
1016 DartPageDebug* pageDebug = lookupPageDebugForCurrentIsolate();
1017 if (!pageDebug)
1018 return;
1019 DartScriptDebugListener* listener = pageDebug->listener();
1020
1021 if (!listener)
1022 return;
1023
1024 // Required as some Dart code executes outside of a valid V8 scope when
1025 // the program is paused due to interrupting a Dart isolate.
1026 V8Scope v8Scope(DartDOMData::current());
1027
1028 Vector<String> breakpointIds;
1029 breakpointIds.append(pageDebug->lookupBreakpointId(dartBreakpointId));
1030 m_executionState = stackTrace;
1031 m_pausedIsolate = isolate;
1032 DartScriptState* scriptState = DartUtilities::currentScriptState();
1033 DartScriptDebugListener::SkipPauseRequest result = listener->didPause(script State, m_executionState, exception ? DartUtilities::dartToScriptValue(exception) : ScriptValue(), breakpointIds);
1034
1035 if (result == DartScriptDebugListener::NoSkip) {
1036 m_runningNestedMessageLoop = true;
1037 runMessageLoopOnPause(isolate);
1038 m_runningNestedMessageLoop = false;
1039 }
1040
1041 m_executionState = 0;
1042 m_pausedIsolate = 0;
1043
1044 if (result == DartScriptDebugListener::StepInto) {
1045 Dart_SetStepInto();
1046 } else if (result == DartScriptDebugListener::StepOut) {
1047 Dart_SetStepOut();
1048 }
1049 }
1050
1051 void DartScriptDebugServer::pausedEventHandler(Dart_IsolateId isolateId, intptr_ t breakpointId, const Dart_CodeLocation& location)
1052 {
1053 DartScriptDebugServer::shared().handleDartDebugEvent(isolateId, breakpointId , 0, location);
1054 }
1055
1056 void DartScriptDebugServer::exceptionHandler(Dart_IsolateId isolateId, Dart_Hand le exception, Dart_StackTrace trace)
1057 {
1058 DartScriptDebugServer::shared().handleException(isolateId, exception, trace) ;
1059 }
1060
1061 void DartScriptDebugServer::isolateEventHandler(Dart_IsolateId isolateId, Dart_I solateEvent kind)
1062 {
1063 if (kind == kInterrupted) {
1064 DartScriptDebugServer::shared().handleInterrupted(isolateId);
1065 }
1066 }
1067
1068 void DartScriptDebugServer::handleInterrupted(Dart_IsolateId isolateId)
1069 {
1070 V8Scope v8Scope(DartDOMData::current());
1071 // FIXME: this is a bit of a hack. V8 was also set to pause on the next
1072 // code execution. If it attempts to pause while in the middle of
1073 // internal V8 debugger logic it will crash so before we do anything we
1074 // need to cancel the pending pause sent to V8.
1075 // Perhaps it would be slightly less hacky to send a message to
1076 // ScriptDebugServer instructing it to cancel pausing V8.
1077 v8::Debug::CancelDebugBreak(DartUtilities::currentV8Context()->GetIsolate()) ;
1078
1079 Dart_Isolate isolate = Dart_GetIsolate(isolateId);
1080 ASSERT(isolate);
1081 DartIsolateScope scope(isolate);
1082 DartApiScope apiScope;
1083
1084 if (!m_interruptCalled.contains(isolate)) {
1085 // Special case when we were interrupted to run pending tasks.
1086 // We need to fake that an interrupt has been called so we don't
1087 // issue an extra spurious interrupt.
1088 m_interruptCalled.add(isolate);
1089 m_interruptCancelled.add(isolate);
1090 }
1091 runPendingTasks();
1092
1093 ASSERT(isolate == Dart_CurrentIsolate());
1094 if (!m_interruptCalled.contains(isolate)) {
1095 return;
1096 }
1097
1098 m_interruptCalled.remove(isolate);
1099 if (m_interruptCancelled.contains(isolate)) {
1100 m_interruptCancelled.remove(isolate);
1101 return;
1102 }
1103
1104 // The user really wants to be paused at the start of the first line of
1105 // the Dart method not at the method invocation itself. Otherwise,
1106 // stepping to the next call steps out of the executing Dart code
1107 // which is not what the user expects.
1108 Dart_SetStepInto();
1109 continueProgram();
1110 }
1111
1112 void DartScriptDebugServer::handleException(Dart_IsolateId isolateId, Dart_Handl e exception, Dart_StackTrace trace)
1113 {
1114 Dart_Isolate isolate = Dart_GetIsolate(isolateId);
1115 ASSERT(isolate);
1116 Dart_CodeLocation location;
1117 Dart_Handle ALLOW_UNUSED result;
1118 Dart_ActivationFrame frame;
1119 result = Dart_GetActivationFrame(trace, 0, &frame);
1120 ASSERT(!Dart_IsError(result));
1121 result = Dart_ActivationFrameGetLocation(frame, 0, 0, &location);
1122 ASSERT(!Dart_IsError(result));
1123 handleProgramBreak(isolate, trace, ILLEGAL_BREAKPOINT_ID, exception, locatio n);
1124 }
1125
1126 void DartScriptDebugServer::runScript(ScriptState* scriptState, const String& sc riptId, ScriptValue* result, bool* wasThrown, String* exceptionDetailsText, int* lineNumber, int* columnNumber, RefPtrWillBeRawPtr<ScriptCallStack>* stackTrace)
1127 {
1128 }
1129
1130 ScriptCallFrame DartScriptDebugServer::getScriptCallFrameHelper(int frameIndex)
1131 {
1132 Dart_ActivationFrame frame = 0;
1133 Dart_Handle result = Dart_GetActivationFrame(0, frameIndex, &frame);
1134 ASSERT(!Dart_IsError(result));
1135 if (Dart_IsError(result))
1136 return ScriptCallFrame();
1137 Dart_Handle functionName = 0;
1138 Dart_Handle function = 0;
1139 Dart_CodeLocation location;
1140 Dart_ActivationFrameGetLocation(frame, &functionName, &function, &location);
1141 const String& url = DartUtilities::toString(location.script_url);
1142 intptr_t line = 0;
1143 intptr_t column = 0;
1144 Dart_ActivationFrameInfo(frame, 0, 0, &line, &column);
1145
1146 Dart_Handle exception = 0;
1147 String functionString = DartUtilities::dartToString(functionName, exception) ;
1148 ASSERT(!exception);
1149 if (exception)
1150 functionString = "Unknown function";
1151 return ScriptCallFrame(functionString, getScriptId(url, Dart_CurrentIsolate( )), url, line - 1, column - 1);
1152 }
1153
1154 }
OLDNEW
« no previous file with comments | « Source/bindings/core/dart/DartScriptDebugServer.h ('k') | Source/bindings/core/dart/DartScriptState.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698