5 package org.chromium.debug.core.model; |
5 package org.chromium.debug.core.model; |
6 |
6 |
7 import java.util.Collection; |
7 import java.util.Collection; |
8 |
8 |
9 import org.chromium.debug.core.ChromiumDebugPlugin; |
9 import org.chromium.debug.core.ChromiumDebugPlugin; |
|
10 import org.chromium.debug.core.ChromiumSourceDirector; |
|
11 import org.chromium.debug.core.model.BreakpointSynchronizer.Callback; |
10 import org.chromium.debug.core.util.ChromiumDebugPluginUtil; |
12 import org.chromium.debug.core.util.ChromiumDebugPluginUtil; |
11 import org.chromium.sdk.Breakpoint; |
13 import org.chromium.sdk.Breakpoint; |
12 import org.chromium.sdk.CallFrame; |
14 import org.chromium.sdk.CallFrame; |
13 import org.chromium.sdk.DebugContext; |
15 import org.chromium.sdk.DebugContext; |
14 import org.chromium.sdk.ExceptionData; |
16 import org.chromium.sdk.ExceptionData; |
15 import org.chromium.sdk.JavascriptVm; |
17 import org.chromium.sdk.JavascriptVm; |
16 import org.chromium.sdk.Script; |
18 import org.chromium.sdk.Script; |
17 import org.chromium.sdk.JavascriptVm.BreakpointCallback; |
19 import org.chromium.sdk.SyncCallback; |
18 import org.chromium.sdk.JavascriptVm.ScriptsCallback; |
20 import org.chromium.sdk.JavascriptVm.ScriptsCallback; |
19 import org.eclipse.core.resources.IFile; |
21 import org.eclipse.core.resources.IFile; |
20 import org.eclipse.core.resources.IMarkerDelta; |
22 import org.eclipse.core.resources.IMarkerDelta; |
21 import org.eclipse.core.resources.IProject; |
23 import org.eclipse.core.resources.IProject; |
22 import org.eclipse.core.runtime.CoreException; |
24 import org.eclipse.core.runtime.CoreException; |
23 import org.eclipse.debug.core.DebugException; |
25 import org.eclipse.debug.core.DebugException; |
24 import org.eclipse.debug.core.DebugPlugin; |
|
25 import org.eclipse.debug.core.IBreakpointManager; |
|
26 import org.eclipse.debug.core.ILaunch; |
26 import org.eclipse.debug.core.ILaunch; |
27 import org.eclipse.debug.core.model.IBreakpoint; |
27 import org.eclipse.debug.core.model.IBreakpoint; |
28 import org.eclipse.debug.core.model.ISourceLocator; |
|
29 import org.eclipse.debug.core.model.IStackFrame; |
|
30 import org.eclipse.osgi.util.NLS; |
28 import org.eclipse.osgi.util.NLS; |
31 |
29 |
32 /** |
30 /** |
33 * Virtual project-supporting implementation of {@link WorkspaceBridge}. |
31 * Virtual project-supporting implementation of {@link WorkspaceBridge}. |
34 */ |
32 */ |
59 } |
57 } |
60 |
58 |
61 private final IProject debugProject; |
59 private final IProject debugProject; |
62 private final JavascriptVm javascriptVm; |
60 private final JavascriptVm javascriptVm; |
63 private final ResourceManager resourceManager; |
61 private final ResourceManager resourceManager; |
64 private final BreakpointRegistry breakpointRegistry = new BreakpointRegistry(); |
|
65 private final DebugTargetImpl debugTargetImpl; |
62 private final DebugTargetImpl debugTargetImpl; |
|
63 private final BreakpointMap.InTargetMap breakpointInTargetMap = new BreakpointMap.InTargetMap(); |
|
64 private final ChromiumSourceDirector sourceDirector; |
66 |
65 |
67 public VProjectWorkspaceBridge(String projectName, DebugTargetImpl debugTargetImpl, |
66 public VProjectWorkspaceBridge(String projectName, DebugTargetImpl debugTargetImpl, |
68 JavascriptVm javascriptVm) { |
67 JavascriptVm javascriptVm) { |
69 this.debugTargetImpl = debugTargetImpl; |
68 this.debugTargetImpl = debugTargetImpl; |
70 this.javascriptVm = javascriptVm; |
69 this.javascriptVm = javascriptVm; |
71 this.debugProject = ChromiumDebugPluginUtil.createEmptyProject(projectName); |
70 this.debugProject = ChromiumDebugPluginUtil.createEmptyProject(projectName); |
72 this.resourceManager = new ResourceManager(debugProject, breakpointRegistry); |
71 this.resourceManager = new ResourceManager(debugProject); |
|
72 |
73 ILaunch launch = debugTargetImpl.getLaunch(); |
73 ILaunch launch = debugTargetImpl.getLaunch(); |
74 launch.setSourceLocator(sourceLocator); |
74 |
|
75 sourceDirector = (ChromiumSourceDirector) launch.getSourceLocator(); |
|
76 sourceDirector.initializeVProjectContainers(debugProject, resourceManager); |
|
77 } |
|
78 |
|
79 public void synchronizeBreakpoints(BreakpointSynchronizer.Direction direction, |
|
80 Callback callback) { |
|
81 BreakpointSynchronizer synchronizer = new BreakpointSynchronizer(javascriptVm, |
|
82 breakpointInTargetMap, sourceDirector, breakpointHandler, DEBUG_MODEL_ID); |
|
83 synchronizer.syncBreakpoints(direction, callback); |
75 } |
84 } |
76 |
85 |
77 public void launchRemoved() { |
86 public void launchRemoved() { |
78 if (debugProject != null) { |
87 if (debugProject != null) { |
79 ChromiumDebugPluginUtil.deleteVirtualProjectAsync(debugProject); |
88 ChromiumDebugPluginUtil.deleteVirtualProjectAsync(debugProject); |
80 } |
89 } |
81 } |
90 } |
82 |
91 |
83 public void beforeDetach() { |
92 public void beforeDetach() { |
84 IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager(); |
|
85 IBreakpoint[] breakpoints = |
|
86 breakpointManager.getBreakpoints(DEBUG_MODEL_ID); |
|
87 for (IBreakpoint bp : breakpoints) { |
|
88 ChromiumLineBreakpoint clb = (ChromiumLineBreakpoint) bp; |
|
89 if (clb.getBrowserBreakpoint() != null && |
|
90 clb.getBrowserBreakpoint().getId() != Breakpoint.INVALID_ID) { |
|
91 clb.getBrowserBreakpoint().clear(null); |
|
92 } |
|
93 } |
|
94 try { |
|
95 breakpointManager.removeBreakpoints(breakpoints, true); |
|
96 } catch (CoreException e) { |
|
97 ChromiumDebugPlugin.log(e); |
|
98 } |
|
99 } |
93 } |
100 |
94 |
101 public void handleVmResetEvent() { |
95 public void handleVmResetEvent() { |
102 resourceManager.clear(); |
96 resourceManager.clear(); |
103 } |
97 } |
121 } |
115 } |
122 } |
116 } |
123 }); |
117 }); |
124 } |
118 } |
125 |
119 |
126 public IFile getScriptResource(Script script) { |
120 public VmResource findVmResourceFromWorkspaceFile(IFile resource) throws CoreException { |
127 return resourceManager.getResource(script); |
121 VmResourceId id = findVmResourceIdFromWorkspaceFile(resource); |
|
122 if (id == null) { |
|
123 return null; |
|
124 } |
|
125 return resourceManager.getVmResource(id); |
|
126 } |
|
127 |
|
128 private VmResourceId findVmResourceIdFromWorkspaceFile(IFile resource) throws CoreException { |
|
129 return sourceDirector.getReverseSourceLookup().findVmResource(resource); |
|
130 } |
|
131 |
|
132 public void reloadScript(Script script) { |
|
133 resourceManager.reloadScript(script); |
128 } |
134 } |
129 |
135 |
130 public BreakpointHandler getBreakpointHandler() { |
136 public BreakpointHandler getBreakpointHandler() { |
131 return breakpointHandler; |
137 return breakpointHandler; |
132 } |
138 } |
133 |
139 |
134 private final BreakpointHandler breakpointHandler = new BreakpointHandler() { |
140 private final BreakpointHandlerImpl breakpointHandler = new BreakpointHandlerImpl(); |
|
141 |
|
142 private class BreakpointHandlerImpl implements BreakpointHandler, |
|
143 BreakpointSynchronizer.BreakpointHelper { |
135 public boolean supportsBreakpoint(IBreakpoint breakpoint) { |
144 public boolean supportsBreakpoint(IBreakpoint breakpoint) { |
136 return DEBUG_MODEL_ID.equals(breakpoint.getModelIdentifier()) && |
145 return DEBUG_MODEL_ID.equals(breakpoint.getModelIdentifier()) && |
137 !debugTargetImpl.isDisconnected(); |
146 !debugTargetImpl.isDisconnected(); |
138 } |
147 } |
|
148 |
|
149 public ChromiumLineBreakpoint tryCastBreakpoint(IBreakpoint breakpoint) { |
|
150 if (!supportsBreakpoint(breakpoint)) { |
|
151 return null; |
|
152 } |
|
153 if (breakpoint instanceof ChromiumLineBreakpoint == false) { |
|
154 return null; |
|
155 } |
|
156 return (ChromiumLineBreakpoint) breakpoint; |
|
157 } |
|
158 |
139 public void breakpointAdded(IBreakpoint breakpoint) { |
159 public void breakpointAdded(IBreakpoint breakpoint) { |
140 if (!supportsBreakpoint(breakpoint)) { |
160 ChromiumLineBreakpoint lineBreakpoint = tryCastBreakpoint(breakpoint); |
141 return; |
161 if (lineBreakpoint == null) { |
142 } |
162 return; |
143 try { |
163 } |
144 if (breakpoint.isEnabled()) { |
164 if (ChromiumLineBreakpoint.getIgnoreList().contains(breakpoint)) { |
145 // Class cast is ensured by the supportsBreakpoint implementation |
165 return; |
146 final ChromiumLineBreakpoint lineBreakpoint = (ChromiumLineBreakpoint) breakpoint; |
166 } |
147 IFile file = (IFile) breakpoint.getMarker().getResource(); |
167 if (!lineBreakpoint.isEnabled()) { |
148 if (resourceManager.isAddingFile(file)) { |
168 return; |
149 return; // restoring breakpoints in progress |
169 } |
|
170 IFile file = (IFile) lineBreakpoint.getMarker().getResource(); |
|
171 VmResourceId vmResourceId; |
|
172 try { |
|
173 vmResourceId = findVmResourceIdFromWorkspaceFile(file); |
|
174 } catch (CoreException e) { |
|
175 ChromiumDebugPlugin.log( |
|
176 new Exception("Failed to resolve script for the file " + file, e)); //$NON-NLS-1$ |
|
177 return; |
|
178 } |
|
179 if (vmResourceId == null) { |
|
180 // Might be a script from a different debug target |
|
181 return; |
|
182 } |
|
183 |
|
184 createBreakpointOnRemote(lineBreakpoint, vmResourceId, null, null); |
|
185 } |
|
186 |
|
187 public void createBreakpointOnRemote(final ChromiumLineBreakpoint lineBreakpoint, |
|
188 final VmResourceId vmResourceId, |
|
189 final CreateCallback createCallback, SyncCallback syncCallback) { |
|
190 try { |
|
191 ChromiumLineBreakpoint.Helper.CreateOnRemoveCallback callback = |
|
192 new ChromiumLineBreakpoint.Helper.CreateOnRemoveCallback() { |
|
193 public void success(Breakpoint breakpoint) { |
|
194 breakpointInTargetMap.add(breakpoint, lineBreakpoint); |
|
195 if (createCallback != null) { |
|
196 createCallback.success(); |
|
197 } |
150 } |
198 } |
151 final Script script = resourceManager.getScript(file); |
199 public void failure(String errorMessage) { |
152 if (script == null) { |
200 if (createCallback == null) { |
153 // Might be a script from a different debug target |
201 ChromiumDebugPlugin.logError(errorMessage); |
154 return; |
202 } else { |
|
203 createCallback.failure(new Exception(errorMessage)); |
|
204 } |
155 } |
205 } |
156 // ILineBreakpoint lines are 1-based while V8 lines are 0-based |
206 }; |
157 final int line = (lineBreakpoint.getLineNumber() - 1) + script.getStartLine(); |
207 |
158 BreakpointCallback callback = new BreakpointCallback() { |
208 ChromiumLineBreakpoint.Helper.createOnRemote(lineBreakpoint, vmResourceId, debugTargetImpl, |
159 public void success(Breakpoint breakpoint) { |
209 callback, syncCallback); |
160 lineBreakpoint.setBreakpoint(breakpoint); |
210 } catch (CoreException e) { |
161 breakpointRegistry.add(script, line, breakpoint); |
211 ChromiumDebugPlugin.log(new Exception("Failed to create breakpoint in " + //$NON-NLS-1$ |
162 } |
212 getTargetNameSafe(), e)); |
163 |
213 } |
164 public void failure(String errorMessage) { |
214 } |
165 ChromiumDebugPlugin.logError(errorMessage); |
215 |
166 } |
216 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { |
167 }; |
217 ChromiumLineBreakpoint lineBreakpoint = tryCastBreakpoint(breakpoint); |
168 if (script.getName() != null) { |
218 if (lineBreakpoint == null) { |
169 javascriptVm.setBreakpoint(Breakpoint.Type.SCRIPT_NAME, |
219 return; |
170 script.getName(), |
220 } |
171 line, |
221 if (ChromiumLineBreakpoint.getIgnoreList().contains(lineBreakpoint)) { |
172 Breakpoint.EMPTY_VALUE, |
222 return; |
173 breakpoint.isEnabled(), |
223 } |
174 lineBreakpoint.getCondition(), |
224 Breakpoint sdkBreakpoint = breakpointInTargetMap.getSdkBreakpoint(lineBreakpoint); |
175 lineBreakpoint.getIgnoreCount(), |
225 if (sdkBreakpoint == null) { |
176 callback); |
226 return; |
177 } else { |
227 } |
178 javascriptVm.setBreakpoint(Breakpoint.Type.SCRIPT_ID, |
228 |
179 String.valueOf(script.getId()), |
229 try { |
180 line, |
230 ChromiumLineBreakpoint.Helper.updateOnRemote(sdkBreakpoint, lineBreakpoint); |
181 Breakpoint.EMPTY_VALUE, |
231 } catch (RuntimeException e) { |
182 breakpoint.isEnabled(), |
232 ChromiumDebugPlugin.log(new Exception("Failed to change breakpoint in " + //$NON-NLS-1$ |
183 lineBreakpoint.getCondition(), |
233 getTargetNameSafe(), e)); |
184 lineBreakpoint.getIgnoreCount(), |
234 } |
185 callback); |
235 |
186 } |
236 } |
|
237 |
|
238 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { |
|
239 ChromiumLineBreakpoint lineBreakpoint = tryCastBreakpoint(breakpoint); |
|
240 if (lineBreakpoint == null) { |
|
241 return; |
|
242 } |
|
243 if (ChromiumLineBreakpoint.getIgnoreList().contains(lineBreakpoint)) { |
|
244 return; |
|
245 } |
|
246 |
|
247 Breakpoint sdkBreakpoint = breakpointInTargetMap.getSdkBreakpoint(lineBreakpoint); |
|
248 if (sdkBreakpoint == null) { |
|
249 return; |
|
250 } |
|
251 |
|
252 try { |
|
253 if (!breakpoint.isEnabled()) { |
|
254 return; |
187 } |
255 } |
188 } catch (CoreException e) { |
256 } catch (CoreException e) { |
189 ChromiumDebugPlugin.log(e); |
257 ChromiumDebugPlugin.log(e); |
190 } |
258 return; |
191 } |
259 } |
192 |
260 JavascriptVm.BreakpointCallback callback = new JavascriptVm.BreakpointCallback() { |
193 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { |
261 public void failure(String errorMessage) { |
194 if (!supportsBreakpoint(breakpoint)) { |
262 ChromiumDebugPlugin.log(new Exception("Failed to remove breakpoint in " + //$NON-NLS-1$ |
195 return; |
263 getTargetNameSafe() + ": " + errorMessage)); //$NON-NLS-1$ |
196 } |
264 } |
197 // Class cast is ensured by the supportsBreakpoint implementation |
265 public void success(Breakpoint breakpoint) { |
198 ((ChromiumLineBreakpoint) breakpoint).changed(); |
266 } |
199 } |
267 }; |
200 |
268 try { |
201 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { |
269 sdkBreakpoint.clear(callback, null); |
202 if (!supportsBreakpoint(breakpoint)) { |
270 } catch (RuntimeException e) { |
203 return; |
271 ChromiumDebugPlugin.log(new Exception("Failed to remove breakpoint in " + //$NON-NLS-1$ |
204 } |
272 getTargetNameSafe(), e)); |
205 try { |
273 } |
206 if (breakpoint.isEnabled()) { |
274 breakpointInTargetMap.remove(lineBreakpoint); |
207 // Class cast is ensured by the supportsBreakpoint implementation |
|
208 ChromiumLineBreakpoint lineBreakpoint = (ChromiumLineBreakpoint) breakpoint; |
|
209 lineBreakpoint.clear(); |
|
210 breakpointRegistry.remove( |
|
211 resourceManager.getScript((IFile) breakpoint.getMarker().getResource()), |
|
212 lineBreakpoint.getLineNumber() - 1, |
|
213 lineBreakpoint.getBrowserBreakpoint()); |
|
214 } |
|
215 } catch (CoreException e) { |
|
216 ChromiumDebugPlugin.log(e); |
|
217 } |
|
218 } |
275 } |
219 |
276 |
220 public void breakpointsHit(Collection<? extends Breakpoint> breakpointsHit) { |
277 public void breakpointsHit(Collection<? extends Breakpoint> breakpointsHit) { |
221 if (breakpointsHit.isEmpty()) { |
278 if (breakpointsHit.isEmpty()) { |
222 return; |
279 return; |
223 } |
280 } |
224 IBreakpoint[] breakpoints = |
281 |
225 DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(DEBUG_MODEL_ID); |
282 for (Breakpoint sdkBreakpoint : breakpointsHit) { |
226 for (IBreakpoint breakpoint : breakpoints) { |
283 ChromiumLineBreakpoint uiBreakpoint = breakpointInTargetMap.getUiBreakpoint(sdkBreakpoint); |
227 ChromiumLineBreakpoint jsBreakpoint = (ChromiumLineBreakpoint) breakpoint; |
284 if (uiBreakpoint != null) { |
228 if (breakpointsHit.contains(jsBreakpoint.getBrowserBreakpoint())) { |
285 uiBreakpoint.setIgnoreCount(-1); // reset ignore count as we've hit it |
229 jsBreakpoint.setIgnoreCount(-1); // reset ignore count as we've hit it |
286 } |
230 } |
287 } |
231 } |
288 } |
232 } |
289 private String getTargetNameSafe() { |
233 }; |
290 try { |
234 |
291 return debugTargetImpl.getLaunch().getLaunchConfiguration().getName(); |
235 public int getLineNumber(CallFrame stackFrame) { |
292 } catch (RuntimeException e) { |
236 // convert 0-based to 1-based |
293 return "<unknown>"; //$NON-NLS-1$ |
237 return stackFrame.getLineNumber() + 1; |
294 } |
238 } |
295 } |
239 |
296 } |
240 /** |
|
241 * This very simple source locator works because we provide our own source files. |
|
242 * We'll have to try harder, once we link with resource js files. |
|
243 */ |
|
244 private final ISourceLocator sourceLocator = new ISourceLocator() { |
|
245 public Object getSourceElement(IStackFrame stackFrame) { |
|
246 if (stackFrame instanceof StackFrame == false) { |
|
247 return null; |
|
248 } |
|
249 StackFrame jsStackFrame = (StackFrame) stackFrame; |
|
250 |
|
251 Script script = jsStackFrame.getCallFrame().getScript(); |
|
252 if (script == null) { |
|
253 return null; |
|
254 } |
|
255 |
|
256 return resourceManager.getResource(script); |
|
257 } |
|
258 }; |
|
259 |
297 |
260 private final static JsLabelProvider LABEL_PROVIDER = new JsLabelProvider() { |
298 private final static JsLabelProvider LABEL_PROVIDER = new JsLabelProvider() { |
261 public String getTargetLabel(DebugTargetImpl debugTarget) { |
299 public String getTargetLabel(DebugTargetImpl debugTarget) { |
262 JavascriptVmEmbedder vmEmbedder = debugTarget.getJavascriptEmbedder(); |
300 JavascriptVmEmbedder vmEmbedder = debugTarget.getJavascriptEmbedder(); |
263 if (vmEmbedder == null) { |
301 if (vmEmbedder == null) { |