OSDN Git Service

Merge WebKit at r78450: Initial merge by git.
[android-x86/external-webkit.git] / Source / WebKit / mac / WebView / WebScriptDebugDelegate.mm
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
48 using namespace JSC;
49 using namespace WebCore;
50
51 // FIXME: these error strings should be public for future use by WebScriptObject and in WebScriptObject.h
52 NSString * const WebScriptErrorDomain = @"WebScriptErrorDomain";
53 NSString * const WebScriptErrorDescriptionKey = @"WebScriptErrorDescription";
54 NSString * 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     const 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->globalExec(), 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