1/* 2 * Copyright (C) 2008 Apple 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 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#import "WebScriptDebugger.h" 30 31#import "WebDelegateImplementationCaching.h" 32#import "WebFrameInternal.h" 33#import "WebScriptDebugDelegate.h" 34#import "WebViewInternal.h" 35#import <JavaScriptCore/DebuggerCallFrame.h> 36#import <JavaScriptCore/JSGlobalObject.h> 37#import <JavaScriptCore/SourceProvider.h> 38#import <WebCore/DOMWindow.h> 39#import <WebCore/Frame.h> 40#import <WebCore/JSDOMWindow.h> 41#import <WebCore/KURL.h> 42#import <WebCore/ScriptController.h> 43 44using namespace JSC; 45using namespace WebCore; 46 47@interface WebScriptCallFrame (WebScriptDebugDelegateInternal) 48- (WebScriptCallFrame *)_initWithGlobalObject:(WebScriptObject *)globalObj debugger:(WebScriptDebugger *)debugger caller:(WebScriptCallFrame *)caller debuggerCallFrame:(const DebuggerCallFrame&)debuggerCallFrame; 49- (void)_setDebuggerCallFrame:(const DebuggerCallFrame&)debuggerCallFrame; 50- (void)_clearDebuggerCallFrame; 51@end 52 53NSString *toNSString(const UString& s) 54{ 55 if (s.isEmpty()) 56 return nil; 57 return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(s.characters()) length:s.length()]; 58} 59 60static NSString *toNSString(SourceProvider* s) 61{ 62 if (!s->length()) 63 return nil; 64 return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(s->data()) length:s->length()]; 65} 66 67// convert UString to NSURL 68static NSURL *toNSURL(const UString& s) 69{ 70 if (s.isEmpty()) 71 return nil; 72 return KURL(ParsedURLString, ustringToString(s)); 73} 74 75static WebFrame *toWebFrame(JSGlobalObject* globalObject) 76{ 77 JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); 78 return kit(window->impl()->frame()); 79} 80 81WebScriptDebugger::WebScriptDebugger(JSGlobalObject* globalObject) 82 : m_callingDelegate(false) 83 , m_globalObject(globalObject->globalData(), globalObject) 84{ 85 attach(globalObject); 86 initGlobalCallFrame(globalObject->globalExec()); 87} 88 89void WebScriptDebugger::initGlobalCallFrame(const DebuggerCallFrame& debuggerCallFrame) 90{ 91 m_callingDelegate = true; 92 93 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 94 95 m_topCallFrame.adoptNS([[WebScriptCallFrame alloc] _initWithGlobalObject:core(webFrame)->script()->windowScriptObject() debugger:this caller:m_topCallFrame.get() debuggerCallFrame:debuggerCallFrame]); 96 m_globalCallFrame = m_topCallFrame; 97 98 WebView *webView = [webFrame webView]; 99 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 100 if (implementations->didEnterCallFrameFunc) 101 CallScriptDebugDelegate(implementations->didEnterCallFrameFunc, webView, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), static_cast<NSInteger>(0), -1, webFrame); 102 103 m_callingDelegate = false; 104} 105 106// callbacks - relay to delegate 107void WebScriptDebugger::sourceParsed(ExecState* exec, SourceProvider* sourceProvider, int errorLine, const UString& errorMsg) 108{ 109 if (m_callingDelegate) 110 return; 111 112 m_callingDelegate = true; 113 114 NSString *nsSource = toNSString(sourceProvider); 115 NSURL *nsURL = toNSURL(sourceProvider->url()); 116 int firstLine = sourceProvider->startPosition().m_line.oneBasedInt(); 117 118 WebFrame *webFrame = toWebFrame(exec->dynamicGlobalObject()); 119 WebView *webView = [webFrame webView]; 120 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 121 122 if (errorLine == -1) { 123 if (implementations->didParseSourceFunc) { 124 if (implementations->didParseSourceExpectsBaseLineNumber) 125 CallScriptDebugDelegate(implementations->didParseSourceFunc, webView, @selector(webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:), nsSource, firstLine, nsURL, sourceProvider->asID(), webFrame); 126 else 127 CallScriptDebugDelegate(implementations->didParseSourceFunc, webView, @selector(webView:didParseSource:fromURL:sourceId:forWebFrame:), nsSource, [nsURL absoluteString], sourceProvider->asID(), webFrame); 128 } 129 } else { 130 NSString* nsErrorMessage = toNSString(errorMsg); 131 NSDictionary *info = [[NSDictionary alloc] initWithObjectsAndKeys:nsErrorMessage, WebScriptErrorDescriptionKey, [NSNumber numberWithUnsignedInt:errorLine], WebScriptErrorLineNumberKey, nil]; 132 NSError *error = [[NSError alloc] initWithDomain:WebScriptErrorDomain code:WebScriptGeneralErrorCode userInfo:info]; 133 134 if (implementations->failedToParseSourceFunc) 135 CallScriptDebugDelegate(implementations->failedToParseSourceFunc, webView, @selector(webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:), nsSource, firstLine, nsURL, error, webFrame); 136 137 [error release]; 138 [info release]; 139 } 140 141 m_callingDelegate = false; 142} 143 144void WebScriptDebugger::callEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 145{ 146 if (m_callingDelegate) 147 return; 148 149 m_callingDelegate = true; 150 151 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 152 153 m_topCallFrame.adoptNS([[WebScriptCallFrame alloc] _initWithGlobalObject:core(webFrame)->script()->windowScriptObject() debugger:this caller:m_topCallFrame.get() debuggerCallFrame:debuggerCallFrame]); 154 155 WebView *webView = [webFrame webView]; 156 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 157 if (implementations->didEnterCallFrameFunc) 158 CallScriptDebugDelegate(implementations->didEnterCallFrameFunc, webView, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 159 160 m_callingDelegate = false; 161} 162 163void WebScriptDebugger::atStatement(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 164{ 165 if (m_callingDelegate) 166 return; 167 168 m_callingDelegate = true; 169 170 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 171 WebView *webView = [webFrame webView]; 172 173 [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame]; 174 175 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 176 if (implementations->willExecuteStatementFunc) 177 CallScriptDebugDelegate(implementations->willExecuteStatementFunc, webView, @selector(webView:willExecuteStatement:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 178 179 m_callingDelegate = false; 180} 181 182void WebScriptDebugger::returnEvent(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber) 183{ 184 if (m_callingDelegate) 185 return; 186 187 m_callingDelegate = true; 188 189 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 190 WebView *webView = [webFrame webView]; 191 192 [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame]; 193 194 WebScriptDebugDelegateImplementationCache* implementations = WebViewGetScriptDebugDelegateImplementations(webView); 195 if (implementations->willLeaveCallFrameFunc) 196 CallScriptDebugDelegate(implementations->willLeaveCallFrameFunc, webView, @selector(webView:willLeaveCallFrame:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 197 198 [m_topCallFrame.get() _clearDebuggerCallFrame]; 199 m_topCallFrame = [m_topCallFrame.get() caller]; 200 201 m_callingDelegate = false; 202} 203 204void WebScriptDebugger::exception(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineNumber, bool hasHandler) 205{ 206 if (m_callingDelegate) 207 return; 208 209 m_callingDelegate = true; 210 211 WebFrame *webFrame = toWebFrame(debuggerCallFrame.dynamicGlobalObject()); 212 WebView *webView = [webFrame webView]; 213 [m_topCallFrame.get() _setDebuggerCallFrame:debuggerCallFrame]; 214 215 WebScriptDebugDelegateImplementationCache* cache = WebViewGetScriptDebugDelegateImplementations(webView); 216 if (cache->exceptionWasRaisedFunc) { 217 if (cache->exceptionWasRaisedExpectsHasHandlerFlag) 218 CallScriptDebugDelegate(cache->exceptionWasRaisedFunc, webView, @selector(webView:exceptionWasRaised:hasHandler:sourceId:line:forWebFrame:), m_topCallFrame.get(), hasHandler, sourceID, lineNumber, webFrame); 219 else 220 CallScriptDebugDelegate(cache->exceptionWasRaisedFunc, webView, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:), m_topCallFrame.get(), sourceID, lineNumber, webFrame); 221 } 222 223 m_callingDelegate = false; 224} 225 226void WebScriptDebugger::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineno) 227{ 228 callEvent(debuggerCallFrame, sourceID, lineno); 229} 230 231void WebScriptDebugger::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, intptr_t sourceID, int lineno) 232{ 233 returnEvent(debuggerCallFrame, sourceID, lineno); 234} 235 236void WebScriptDebugger::didReachBreakpoint(const DebuggerCallFrame&, intptr_t, int) 237{ 238 return; 239} 240