|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style license that can be |
|
3 // found in the LICENSE file. |
|
4 |
|
5 package org.chromium.debug.core.model; |
|
6 |
|
7 import java.util.List; |
|
8 |
|
9 import org.chromium.debug.core.ChromiumDebugPlugin; |
|
10 import org.chromium.sdk.CallFrame; |
|
11 import org.chromium.sdk.DebugContext.StepAction; |
|
12 import org.eclipse.core.runtime.IAdaptable; |
|
13 import org.eclipse.debug.core.DebugEvent; |
|
14 import org.eclipse.debug.core.DebugException; |
|
15 import org.eclipse.debug.core.model.IBreakpoint; |
|
16 import org.eclipse.debug.core.model.IStackFrame; |
|
17 import org.eclipse.debug.core.model.IThread; |
|
18 import org.eclipse.osgi.util.NLS; |
|
19 |
|
20 /** |
|
21 * This class represents the only Chromium V8 VM thread. |
|
22 */ |
|
23 public class JavascriptThread extends DebugElementImpl implements IThread, IAdaptable { |
|
24 |
|
25 private static final StackFrame[] EMPTY_FRAMES = new StackFrame[0]; |
|
26 |
|
27 /** |
|
28 * Breakpoints this thread is suspended at or <code>null</code> if none. |
|
29 */ |
|
30 private IBreakpoint[] breakpoints; |
|
31 |
|
32 /** |
|
33 * Whether this thread is stepping. V8 does not provide information if the |
|
34 * thread is actually stepping or it is running past the last "steppable" |
|
35 * statement. |
|
36 */ |
|
37 private boolean isStepping = false; |
|
38 |
|
39 /** |
|
40 * Cached stack |
|
41 */ |
|
42 private StackFrame[] stackFrames; |
|
43 |
|
44 /** |
|
45 * Constructs a new thread for the given target |
|
46 * |
|
47 * @param debugTarget this thread is created for |
|
48 */ |
|
49 public JavascriptThread(IChromiumDebugTarget debugTarget) { |
|
50 super(debugTarget); |
|
51 } |
|
52 |
|
53 public StackFrame[] getStackFrames() throws DebugException { |
|
54 if (isSuspended()) { |
|
55 ensureStackFrames(); |
|
56 return stackFrames; |
|
57 } else { |
|
58 return EMPTY_FRAMES; |
|
59 } |
|
60 } |
|
61 |
|
62 public void reset() { |
|
63 this.stackFrames = null; |
|
64 } |
|
65 |
|
66 private void ensureStackFrames() { |
|
67 this.stackFrames = wrapStackFrames(getDebugTarget().getDebugContext().getCallFrames()); |
|
68 } |
|
69 |
|
70 private StackFrame[] wrapStackFrames(List<? extends CallFrame> jsFrames) { |
|
71 StackFrame[] frames = new StackFrame[jsFrames.size()]; |
|
72 for (int i = 0, size = frames.length; i < size; ++i) { |
|
73 frames[i] = new StackFrame(getDebugTarget(), this, jsFrames.get(i)); |
|
74 } |
|
75 return frames; |
|
76 } |
|
77 |
|
78 public boolean hasStackFrames() throws DebugException { |
|
79 return isSuspended(); |
|
80 } |
|
81 |
|
82 public int getPriority() throws DebugException { |
|
83 return 0; |
|
84 } |
|
85 |
|
86 public IStackFrame getTopStackFrame() throws DebugException { |
|
87 IStackFrame[] frames = getStackFrames(); |
|
88 if (frames.length > 0) { |
|
89 return frames[0]; |
|
90 } |
|
91 return null; |
|
92 } |
|
93 |
|
94 public String getName() throws DebugException { |
|
95 String url = getDebugTarget().getJavascriptEmbedder().getThreadName(); |
|
96 return NLS.bind(Messages.JsThread_ThreadLabelFormat, (isSuspended() |
|
97 ? Messages.JsThread_ThreadLabelSuspended |
|
98 : Messages.JsThread_ThreadLabelRunning), (url.length() > 0 |
|
99 ? (" : " + url) : "")); //$NON-NLS-1$ //$NON-NLS-2$ |
|
100 } |
|
101 |
|
102 public IBreakpoint[] getBreakpoints() { |
|
103 if (breakpoints == null) { |
|
104 return new IBreakpoint[0]; |
|
105 } |
|
106 return breakpoints; |
|
107 } |
|
108 |
|
109 protected void setBreakpoints(IBreakpoint[] breakpoints) { |
|
110 this.breakpoints = breakpoints; |
|
111 } |
|
112 |
|
113 public boolean canResume() { |
|
114 return isSuspended(); |
|
115 } |
|
116 |
|
117 public boolean canSuspend() { |
|
118 return getDebugTarget().canSuspend(); |
|
119 } |
|
120 |
|
121 public boolean isSuspended() { |
|
122 return getDebugTarget().isSuspended(); |
|
123 } |
|
124 |
|
125 public void resume() throws DebugException { |
|
126 setStepping(false); |
|
127 getDebugTarget().resume(); |
|
128 } |
|
129 |
|
130 public void suspend() throws DebugException { |
|
131 getDebugTarget().suspend(); |
|
132 } |
|
133 |
|
134 public boolean canStepInto() { |
|
135 return isSuspended(); |
|
136 } |
|
137 |
|
138 public boolean canStepOver() { |
|
139 return isSuspended(); |
|
140 } |
|
141 |
|
142 public boolean canStepReturn() { |
|
143 return isSuspended(); |
|
144 } |
|
145 |
|
146 public boolean isStepping() { |
|
147 return isStepping; |
|
148 } |
|
149 |
|
150 private void step(StepAction stepAction, int detail) throws DebugException { |
|
151 setStepping(true); |
|
152 getDebugTarget().getDebugContext().continueVm(stepAction, 1, null); |
|
153 // The suspend event should be fired once the backtrace is ready |
|
154 // (in BacktraceProcessor). |
|
155 getDebugTarget().fireResumeEvent(detail); |
|
156 } |
|
157 |
|
158 public void stepInto() throws DebugException { |
|
159 step(StepAction.IN, DebugEvent.STEP_INTO); |
|
160 } |
|
161 |
|
162 public void stepOver() throws DebugException { |
|
163 step(StepAction.OVER, DebugEvent.STEP_OVER); |
|
164 } |
|
165 |
|
166 public void stepReturn() throws DebugException { |
|
167 step(StepAction.OUT, DebugEvent.STEP_RETURN); |
|
168 } |
|
169 |
|
170 public boolean canTerminate() { |
|
171 return getDebugTarget().canTerminate(); |
|
172 } |
|
173 |
|
174 public boolean isTerminated() { |
|
175 return getDebugTarget().isTerminated(); |
|
176 } |
|
177 |
|
178 public void terminate() throws DebugException { |
|
179 getDebugTarget().terminate(); |
|
180 } |
|
181 |
|
182 /** |
|
183 * Sets whether this thread is stepping. |
|
184 */ |
|
185 protected void setStepping(boolean stepping) { |
|
186 isStepping = stepping; |
|
187 } |
|
188 |
|
189 @Override |
|
190 @SuppressWarnings("unchecked") |
|
191 public Object getAdapter(Class adapter) { |
|
192 if (adapter == StackFrame.class) { |
|
193 try { |
|
194 return getTopStackFrame(); |
|
195 } catch (DebugException e) { |
|
196 ChromiumDebugPlugin.log(e); |
|
197 } |
|
198 } |
|
199 return super.getAdapter(adapter); |
|
200 } |
|
201 } |