1/* 2 * Copyright (C) 2005 Apple Computer, 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 "WebDataSource.h" 30#import "WebDataSourceInternal.h" 31#import "WebFrameInternal.h" 32#import "WebScriptDebugDelegate.h" 33#import "WebScriptDebugger.h" 34#import "WebViewInternal.h" 35#import <WebCore/Frame.h> 36#import <WebCore/ScriptController.h> 37#import <WebCore/WebScriptObjectPrivate.h> 38#import <WebCore/runtime_root.h> 39#import <debugger/Debugger.h> 40#import <debugger/DebuggerActivation.h> 41#import <debugger/DebuggerCallFrame.h> 42#import <interpreter/CallFrame.h> 43#import <runtime/Completion.h> 44#import <runtime/JSFunction.h> 45#import <runtime/JSGlobalObject.h> 46#import <runtime/JSLock.h> 47 48using namespace JSC; 49using namespace WebCore; 50 51// FIXME: these error strings should be public for future use by WebScriptObject and in WebScriptObject.h 52NSString * const WebScriptErrorDomain = @"WebScriptErrorDomain"; 53NSString * const WebScriptErrorDescriptionKey = @"WebScriptErrorDescription"; 54NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber"; 55 56@interface WebScriptCallFrame (WebScriptDebugDelegateInternal) 57 58- (id)_convertValueToObjcValue:(JSValue)value; 59 60@end 61 62@interface WebScriptCallFramePrivate : NSObject { 63@public 64 WebScriptObject *globalObject; // the global object's proxy (not retained) 65 WebScriptCallFrame *caller; // previous stack frame 66 DebuggerCallFrame* debuggerCallFrame; 67 WebScriptDebugger* debugger; 68} 69@end 70 71@implementation WebScriptCallFramePrivate 72- (void)dealloc 73{ 74 [caller release]; 75 delete debuggerCallFrame; 76 [super dealloc]; 77} 78@end 79 80// WebScriptCallFrame 81// 82// One of these is created to represent each stack frame. Additionally, there is a "global" 83// frame to represent the outermost scope. This global frame is always the last frame in 84// the chain of callers. 85// 86// The delegate can assign a "wrapper" to each frame object so it can relay calls through its 87// own exported interface. This class is private to WebCore (and the delegate). 88 89@implementation WebScriptCallFrame (WebScriptDebugDelegateInternal) 90 91- (WebScriptCallFrame *)_initWithGlobalObject:(WebScriptObject *)globalObj debugger:(WebScriptDebugger *)debugger caller:(WebScriptCallFrame *)caller debuggerCallFrame:(const DebuggerCallFrame&)debuggerCallFrame 92{ 93 if ((self = [super init])) { 94 _private = [[WebScriptCallFramePrivate alloc] init]; 95 _private->globalObject = globalObj; 96 _private->caller = [caller retain]; 97 _private->debugger = debugger; 98 } 99 return self; 100} 101 102- (void)_setDebuggerCallFrame:(const DebuggerCallFrame&)debuggerCallFrame 103{ 104 if (!_private->debuggerCallFrame) 105 _private->debuggerCallFrame = new DebuggerCallFrame(debuggerCallFrame); 106 else 107 *_private->debuggerCallFrame = debuggerCallFrame; 108} 109 110- (void)_clearDebuggerCallFrame 111{ 112 delete _private->debuggerCallFrame; 113 _private->debuggerCallFrame = 0; 114} 115 116- (id)_convertValueToObjcValue:(JSValue)value 117{ 118 if (!value) 119 return nil; 120 121 WebScriptObject *globalObject = _private->globalObject; 122 if (value == [globalObject _imp]) 123 return globalObject; 124 125 Bindings::RootObject* root1 = [globalObject _originRootObject]; 126 if (!root1) 127 return nil; 128 129 Bindings::RootObject* root2 = [globalObject _rootObject]; 130 if (!root2) 131 return nil; 132 133 return [WebScriptObject _convertValueToObjcValue:value originRootObject:root1 rootObject:root2]; 134} 135 136@end 137 138 139 140@implementation WebScriptCallFrame 141 142- (void) dealloc 143{ 144 [_userInfo release]; 145 [_private release]; 146 [super dealloc]; 147} 148 149- (void)setUserInfo:(id)userInfo 150{ 151 if (userInfo != _userInfo) { 152 [_userInfo release]; 153 _userInfo = [userInfo retain]; 154 } 155} 156 157- (id)userInfo 158{ 159 return _userInfo; 160} 161 162- (WebScriptCallFrame *)caller 163{ 164 return _private->caller; 165} 166 167// Returns an array of scope objects (most local first). 168// The properties of each scope object are the variables for that scope. 169// Note that the last entry in the array will _always_ be the global object (windowScriptObject), 170// whose properties are the global variables. 171 172- (NSArray *)scopeChain 173{ 174 if (!_private->debuggerCallFrame) 175 return [NSArray array]; 176 177 JSLock lock(SilenceAssertionsOnly); 178 179 ScopeChainNode* scopeChain = _private->debuggerCallFrame->scopeChain(); 180 if (!scopeChain->next) // global frame 181 return [NSArray arrayWithObject:_private->globalObject]; 182 183 NSMutableArray *scopes = [[NSMutableArray alloc] init]; 184 185 ScopeChainIterator end = scopeChain->end(); 186 for (ScopeChainIterator it = scopeChain->begin(); it != end; ++it) { 187 JSObject* object = it->get(); 188 if (object->isActivationObject()) 189 object = new (scopeChain->globalData) DebuggerActivation(*scopeChain->globalData, object); 190 [scopes addObject:[self _convertValueToObjcValue:object]]; 191 } 192 193 NSArray *result = [NSArray arrayWithArray:scopes]; 194 [scopes release]; 195 return result; 196} 197 198// Returns the name of the function for this frame, if available. 199// Returns nil for anonymous functions and for the global frame. 200 201- (NSString *)functionName 202{ 203 if (!_private->debuggerCallFrame) 204 return nil; 205 206 const UString* functionName = _private->debuggerCallFrame->functionName(); 207 return functionName ? toNSString(*functionName) : nil; 208} 209 210// Returns the pending exception for this frame (nil if none). 211 212- (id)exception 213{ 214 if (!_private->debuggerCallFrame) 215 return nil; 216 217 JSValue exception = _private->debuggerCallFrame->exception(); 218 return exception ? [self _convertValueToObjcValue:exception] : nil; 219} 220 221// Evaluate some JavaScript code in the context of this frame. 222// The code is evaluated as if by "eval", and the result is returned. 223// If there is an (uncaught) exception, it is returned as though _it_ were the result. 224// Calling this method on the global frame is not quite the same as calling the WebScriptObject 225// method of the same name, due to the treatment of exceptions. 226 227- (id)evaluateWebScript:(NSString *)script 228{ 229 if (!_private->debuggerCallFrame) 230 return nil; 231 232 JSLock lock(SilenceAssertionsOnly); 233 234 // If this is the global call frame and there is no dynamic global object, 235 // Dashcode is attempting to execute JS in the evaluator using a stale 236 // WebScriptCallFrame. Instead, we need to set the dynamic global object 237 // and evaluate the JS in the global object's global call frame. 238 JSGlobalObject* globalObject = _private->debugger->globalObject(); 239 if (self == _private->debugger->globalCallFrame() && !globalObject->globalData().dynamicGlobalObject) { 240 JSGlobalObject* globalObject = _private->debugger->globalObject(); 241 242 DynamicGlobalObjectScope globalObjectScope(globalObject->globalData(), globalObject); 243 244 JSValue exception; 245 JSValue result = evaluateInGlobalCallFrame(stringToUString(script), exception, globalObject); 246 if (exception) 247 return [self _convertValueToObjcValue:exception]; 248 return result ? [self _convertValueToObjcValue:result] : nil; 249 } 250 251 JSValue exception; 252 JSValue result = _private->debuggerCallFrame->evaluate(stringToUString(script), exception); 253 if (exception) 254 return [self _convertValueToObjcValue:exception]; 255 return result ? [self _convertValueToObjcValue:result] : nil; 256} 257 258@end 259