Home | History | Annotate | Download | only in WebView
      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     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