Reviewed by Kevin Decker.
authorthatcher <thatcher@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Jun 2006 17:34:54 +0000 (17:34 +0000)
committerthatcher <thatcher@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Jun 2006 17:34:54 +0000 (17:34 +0000)
        Code clean up. Adds the stackframe and makes only the body
        of the tables scrollable keeping the header visible.
        Shows the current function stack when paused or stepping.

        * Drosera/DebuggerApplication.m:
        (-[DebuggerApplication awakeFromNib]):
        (-[DebuggerApplication numberOfRowsInTableView:]):
        (-[DebuggerApplication tableView:objectValueForTableColumn:row:]):
        * Drosera/DebuggerDocument.h:
        * Drosera/DebuggerDocument.m:
        (-[DebuggerDocument dealloc]):
        (-[DebuggerDocument currentFrame]):
        (-[DebuggerDocument currentFrameFunctionName]):
        (-[DebuggerDocument currentFunctionStack]):
        (-[DebuggerDocument log:]):
        (-[DebuggerDocument windowWillClose:]):
        (-[DebuggerDocument webView:didEnterCallFrame:sourceId:line:forWebFrame:]):
        (-[DebuggerDocument webView:willLeaveCallFrame:sourceId:line:forWebFrame:]):
        * Drosera/Drosera.xcodeproj/project.pbxproj:
        * Drosera/debugger.css:
        * Drosera/debugger.html:
        * Drosera/debugger.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@14972 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKitTools/ChangeLog
WebKitTools/Drosera/DebuggerApplication.m
WebKitTools/Drosera/DebuggerDocument.h
WebKitTools/Drosera/DebuggerDocument.m
WebKitTools/Drosera/Drosera.xcodeproj/project.pbxproj
WebKitTools/Drosera/debugger.css
WebKitTools/Drosera/debugger.html
WebKitTools/Drosera/debugger.js

index 12f8e70753145c89f6291139e1084f43b0653fb0..ae4e34f4a1dcf789828707b97a9ecf835a5d2993 100644 (file)
@@ -1,3 +1,30 @@
+2006-06-22  Timothy Hatcher  <timothy@apple.com>
+
+        Reviewed by Kevin Decker.
+
+        Code clean up. Adds the stackframe and makes only the body
+        of the tables scrollable keeping the header visible.
+        Shows the current function stack when paused or stepping.
+
+        * Drosera/DebuggerApplication.m:
+        (-[DebuggerApplication awakeFromNib]):
+        (-[DebuggerApplication numberOfRowsInTableView:]):
+        (-[DebuggerApplication tableView:objectValueForTableColumn:row:]):
+        * Drosera/DebuggerDocument.h:
+        * Drosera/DebuggerDocument.m:
+        (-[DebuggerDocument dealloc]):
+        (-[DebuggerDocument currentFrame]):
+        (-[DebuggerDocument currentFrameFunctionName]):
+        (-[DebuggerDocument currentFunctionStack]):
+        (-[DebuggerDocument log:]):
+        (-[DebuggerDocument windowWillClose:]):
+        (-[DebuggerDocument webView:didEnterCallFrame:sourceId:line:forWebFrame:]):
+        (-[DebuggerDocument webView:willLeaveCallFrame:sourceId:line:forWebFrame:]):
+        * Drosera/Drosera.xcodeproj/project.pbxproj:
+        * Drosera/debugger.css:
+        * Drosera/debugger.html:
+        * Drosera/debugger.js:
+
 2006-06-22  Alexey Proskuryakov  <ap@nypop.com>
 
         Reviewed by Anders.
index 8b436e063f1d22f6ab163d164d56a5ba37ab01a6..b15964d92223eeab2a2057499f82db2c6ef983a8 100644 (file)
 #import <WebKit/WebCoreStatistics.h>
 
 @implementation DebuggerApplication
+- (void)awakeFromNib
+{
+    NSTableColumn *column = [attachTable tableColumnWithIdentifier:@"name"];
+    NSBrowserCell *cell = [[NSBrowserCell alloc] init];
+    [cell setLeaf:YES];
+    [column setDataCell:cell];
+    [cell release];
+}
+
 - (void)applicationDidFinishLaunching:(NSNotification *)notification
 {
     [WebCoreStatistics setShouldPrintExceptions:YES];
@@ -43,6 +52,9 @@
     [[NSDistributedNotificationCenter defaultCenter] postNotificationName:WebScriptDebugServerQueryNotification object:nil];
 }
 
+#pragma mark -
+#pragma mark Server Detection Callbacks
+
 - (void)serverLoaded:(NSNotification *)notification
 {
     int processId = [[[notification userInfo] objectForKey:WebScriptDebugServerProcessIdentifierKey] intValue];
     [attachTable reloadData];
 }
 
-- (void)awakeFromNib
-{
-    NSTableColumn *column = [attachTable tableColumnWithIdentifier:@"name"];
-    NSBrowserCell *cell = [[NSBrowserCell alloc] init];
-    [cell setLeaf:YES];
-    [column setDataCell:cell];
-    [cell release];
-}
+#pragma mark -
+#pragma mark Attach Panel Actions
 
 - (IBAction)showAttachPanel:(id)sender
 {
     [document showWindow:sender];
 }
 
-- (int) numberOfRowsInTableView:(NSTableView *)tableView
+#pragma mark -
+#pragma mark Table View Delegate
+
+- (int)numberOfRowsInTableView:(NSTableView *)tableView
 {
     return [knownServerNames count];
 }
 
-- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
+- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
 {
     return @"";
 }
index 72ded6244e7d45007d1342d5234ff62af5150e59..6e506067d16a839870e36d8eed1fa31fac73dc4f 100644 (file)
@@ -30,6 +30,7 @@
 {
     IBOutlet WebView *webView;
     id<WebScriptDebugServer> server;
+    WebScriptCallFrame *currentFrame;
     NSString *currentServerName;
     BOOL webViewLoaded;
     BOOL paused;
index fac97a7a9ccdced84b16409ace22c8ebc099bb3e..6df2244631b8909c45c528d24694dd4a129f71e4 100644 (file)
 
 #import "DebuggerDocument.h"
 
-@implementation WebScriptCallFrame (WebScriptCallFrameScripting)
-+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
-{
-    return NO;
-}
-
-+ (BOOL)isKeyExcludedFromWebScript:(const char *)name
-{
-    return NO;
-}
-@end
-
 @implementation DebuggerDocument
 + (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
 {
@@ -51,6 +39,8 @@
     return NO;
 }
 
+#pragma mark -
+
 - (id)initWithServerName:(NSString *)serverName
 {
     if ((self = [super init]))
     return self;
 }
 
-- (void)windowWillClose:(NSNotification *)notification
+- (void)dealloc
 {
-    [[webView windowScriptObject] removeWebScriptKey:@"DebuggerDocument"];
+    [server release];
+    [currentServerName release];
+    [super dealloc];
+}
 
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillTerminateNotification object:nil];
-    [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:WebScriptDebugServerQueryReplyNotification object:nil];
-    [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:WebScriptDebugServerWillUnloadNotification object:nil];
+#pragma mark -
+#pragma mark Stack & Variables
 
-    [self switchToServerNamed:nil];
+- (WebScriptCallFrame *)currentFrame
+{
+    return currentFrame;
+}
 
-    [self autorelease]; // DebuggerApplication expects us to release on close
+- (NSString *)currentFrameFunctionName
+{
+    return [currentFrame functionName];
 }
 
-- (void)dealloc
+- (NSArray *)currentFunctionStack
 {
-    [server release];
-    [currentServerName release];
-    [super dealloc];
+    NSMutableArray *result = [[NSMutableArray alloc] init];
+    WebScriptCallFrame *frame = currentFrame;
+    while (frame) {
+        if ([frame functionName])
+            [result addObject:[frame functionName]];
+        frame = [frame caller];
+    }
+    return [result autorelease];
 }
 
+#pragma mark -
+#pragma mark Pause & Step
+
 - (BOOL)isPaused
 {
     return paused;
         [server step];
 }
 
+- (void)log:(NSString *)msg
+{
+    NSLog(@"%@", msg);
+}
+
+#pragma mark -
+#pragma mark Window Controller Overrides
+
 - (NSString *)windowNibName
 {
     return @"Debugger";
     [[webView mainFrame] loadRequest:[[[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath:path]] autorelease]];
 }
 
+
+- (void)windowWillClose:(NSNotification *)notification
+{
+    [[webView windowScriptObject] removeWebScriptKey:@"DebuggerDocument"];
+
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillTerminateNotification object:nil];
+    [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:WebScriptDebugServerQueryReplyNotification object:nil];
+    [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:WebScriptDebugServerWillUnloadNotification object:nil];
+
+    [self switchToServerNamed:nil];
+
+    [self autorelease]; // DebuggerApplication expects us to release on close
+}
+
+#pragma mark -
+#pragma mark Connection Handling
+
 - (void)switchToServerNamed:(NSString *)name
 {
     if (server) {
     [self switchToServerNamed:nil];
 }
 
+#pragma mark -
+#pragma mark WebView Frame Load Delegate
+
 - (void)webView:(WebView *)sender windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
 {
     // note: this is the Debuggers's own WebView, not the one being debugged
     webViewLoaded = YES;
 }
 
+#pragma mark -
+#pragma mark Debug Listener Callbacks
+
 - (void)webView:(WebView *)view didParseSource:(NSString *)source fromURL:(NSString *)url sourceId:(int)sid forWebFrame:(WebFrame *)webFrame
 {
     if (!webViewLoaded)
     if (!webViewLoaded)
         return;
 
+    id old = currentFrame;
+    currentFrame = [frame retain];
+    [old release];
+
     NSArray *args = [NSArray arrayWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
     [[webView windowScriptObject] callWebScriptMethod:@"didEnterCallFrame" withArguments:args];
 }
 
     NSArray *args = [NSArray arrayWithObjects:[NSNumber numberWithInt:sid], [NSNumber numberWithInt:lineno], nil];
     [[webView windowScriptObject] callWebScriptMethod:@"willLeaveCallFrame" withArguments:args];
+
+    id old = currentFrame;
+    currentFrame = [[frame caller] retain];
+    [old release];
 }
 @end
index 1f9820b271f46637be8cf3f83e69ba7867c6c4c7..28d9a5fcc4c49aacdea25aee61b0cb05f1da391a 100644 (file)
@@ -7,6 +7,11 @@
        objects = {
 
 /* Begin PBXBuildFile section */
+               1C2632D30A4AF0A800EA7CD8 /* verticalSplitterBar.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 1C2632D10A4AF0A800EA7CD8 /* verticalSplitterBar.tiff */; };
+               1C2632D40A4AF0A800EA7CD8 /* verticalSplitterDimple.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 1C2632D20A4AF0A800EA7CD8 /* verticalSplitterDimple.tiff */; };
+               1C2632D70A4AF0B800EA7CD8 /* SourceArrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C2632D50A4AF0B800EA7CD8 /* SourceArrow.png */; };
+               1C2632D80A4AF0B800EA7CD8 /* SourceArrowBlank.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C2632D60A4AF0B800EA7CD8 /* SourceArrowBlank.png */; };
+               1C2632DA0A4AF0D200EA7CD8 /* background_stripe.png in Resources */ = {isa = PBXBuildFile; fileRef = 1C2632D90A4AF0D200EA7CD8 /* background_stripe.png */; };
                1C27ABC60A413B720016ECF4 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C27ABC50A413B720016ECF4 /* WebKit.framework */; };
                1C27AC200A413D2D0016ECF4 /* debugger.html in Resources */ = {isa = PBXBuildFile; fileRef = 1C27AC1F0A413D2D0016ECF4 /* debugger.html */; };
                1C27B1260A421D870016ECF4 /* debugger.js in Resources */ = {isa = PBXBuildFile; fileRef = 1C27AC230A413D660016ECF4 /* debugger.js */; };
 /* Begin PBXFileReference section */
                1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
                13E42FBA07B3F13500E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
+               1C2632D10A4AF0A800EA7CD8 /* verticalSplitterBar.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = verticalSplitterBar.tiff; sourceTree = "<group>"; };
+               1C2632D20A4AF0A800EA7CD8 /* verticalSplitterDimple.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = verticalSplitterDimple.tiff; sourceTree = "<group>"; };
+               1C2632D50A4AF0B800EA7CD8 /* SourceArrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = SourceArrow.png; sourceTree = "<group>"; };
+               1C2632D60A4AF0B800EA7CD8 /* SourceArrowBlank.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = SourceArrowBlank.png; sourceTree = "<group>"; };
+               1C2632D90A4AF0D200EA7CD8 /* background_stripe.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background_stripe.png; sourceTree = "<group>"; };
                1C27ABC50A413B720016ECF4 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = /System/Library/Frameworks/WebKit.framework; sourceTree = "<absolute>"; };
                1C27AC1F0A413D2D0016ECF4 /* debugger.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = debugger.html; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                1C27AC230A413D660016ECF4 /* debugger.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = debugger.js; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                                1CC058EA0A44A210006FE533 /* stepOver.tif */,
                                1CC058EB0A44A210006FE533 /* stop.tif */,
                                1CC0596F0A44A485006FE533 /* toolbarBackground.png */,
+                               1C2632D10A4AF0A800EA7CD8 /* verticalSplitterBar.tiff */,
+                               1C2632D20A4AF0A800EA7CD8 /* verticalSplitterDimple.tiff */,
+                               1C2632D50A4AF0B800EA7CD8 /* SourceArrow.png */,
+                               1C2632D60A4AF0B800EA7CD8 /* SourceArrowBlank.png */,
+                               1C2632D90A4AF0D200EA7CD8 /* background_stripe.png */,
                        );
                        path = Images;
                        sourceTree = "<group>";
                                1C4FFE5F0A466F5D0000D05D /* programCounterBreakPointDisabled.tif in Resources */,
                                1C74F0350A47BF8300FEC632 /* viewer.html in Resources */,
                                1C74F04B0A47BFE800FEC632 /* viewer.css in Resources */,
+                               1C2632D30A4AF0A800EA7CD8 /* verticalSplitterBar.tiff in Resources */,
+                               1C2632D40A4AF0A800EA7CD8 /* verticalSplitterDimple.tiff in Resources */,
+                               1C2632D70A4AF0B800EA7CD8 /* SourceArrow.png in Resources */,
+                               1C2632D80A4AF0B800EA7CD8 /* SourceArrowBlank.png in Resources */,
+                               1C2632DA0A4AF0D200EA7CD8 /* background_stripe.png in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index b915ff85b48934b43b42514b738c9a3b9f25459c..0f87b7d7a237e72f5766a00b0045985206a42061 100644 (file)
@@ -41,7 +41,7 @@ body { margin: 0; padding: 0; }
 #header { vertical-align: top; height: 16px; box-sizing: border-box; border-bottom: 1px solid #aaa; background: url(glossyHeader.png) repeat-x; position: absolute; top: 0; left: 0; right: 0; }
 #header > * { vertical-align: top; }
 #footer { height: 21px; box-sizing: border-box; border-top: 1px solid #aaa; background: url(glossyFooterFill.tif) repeat-x; position: absolute; bottom: 0; left: 0; right: 0; }
-#infoDivider { position:absolute; right:0; left:0; top:0; bottom:0; width:10px; cursor: move; background: url(verticalSplitterDimple.tiff) 50% no-repeat, url(verticalSplitterBar.tiff) repeat-y; width: 10px; }
+#infoDivider { position: absolute; z-index: 10; right: 0; left: 0; top: 0; bottom: 9px; width: 10px; cursor: move; background: url(verticalSplitterDimple.tiff) 50% no-repeat, url(verticalSplitterBar.tiff) repeat-y; width: 10px; }
 
 #files {
     opacity: 0;
@@ -123,80 +123,109 @@ button.nav.left:active {
 }
 
 #leftPane {
- position:absolute;
- overflow:scroll;
- top:0;
- bottom:10px;
- left:0;
- width:353px;
- padding:0;
- margin:0;
- }
-.infoBackground {
- background: url(background_stripe.png) repeat;
- position:absolute;
- top:16px;
- bottom:0;
- right:0;
- left:0px;
- padding:0;
- margin:0;
- z-index:-1;
- }
+    position: absolute;
+    top: 0;
+    bottom: 10px;
+    left: 0;
+    width: 253px;
+    padding: 0;
+    margin: 0;
+}
 
 #rightPane {
- position:absolute;
- top:0;
- bottom:0;
- right:0;
- left:353px;
- padding:0;
- margin:0;
- }
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    right: 0;
+    left: 253px;
+    padding: 0;
+    margin: 0;
+}
+
+#stackframe {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    right: 0;
+    left: 0;
+}
+
+#stackframeBody {
+    overflow-y: scroll;
+    overflow-x: hidden;
+    position: absolute;
+    top: 16px;
+    bottom: 0;
+    right: 0;
+    left: 0;
+}
 
 #variables {
- overflow:scroll;
- position:absolute;
- top:0;
- bottom:10px;
- right:0;
- left:10px;
- padding:0;
- margin:0;
- }
+    position: absolute;
+    top: 0;
+    bottom: 10px;
+    right: 0;
+    left: 10px;
+}
 
-td {
- font-family: "lucida grande";
- font-size: 8pt;
- padding: 3px 8px;
- border-left: 1px solid #d9d9d9;
+#variablesBody {
+    overflow-y: scroll;
+    overflow-x: hidden;
+    position: absolute;
+    top: 16px;
+    bottom: 0;
+    right: 0;
+    left: 0;
 }
 
-.multivariable {
-list-style-image:url(SourceArrow.png);
+.infoBackground {
+    background: url(background_stripe.png) repeat;
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    right: 0;
+    left: 0;
+    z-index: -1;
 }
 
-#variablesTable
-{
-width:100%;
+table {
+    font-family: "Lucida Grande", sans-serif;
+    font-size: 11px;
+    border-collapse: collapse;
+    border-spacing: 0;
+    width: 100%;
+    padding: 0;
+    margin: 0;
+    border: 0;
 }
 
-.column th {
- background: url(glossyHeader.png) repeat-x;
- border-right: 1px solid #d9d9d9;
- height: 16px; 
- box-sizing: border-box; 
- border-bottom: 1px solid #aaa;
- font-family: "lucida grande";
- font-size: 8pt;
- font-weight:normal;
- vertical-align:middle;
- padding:0 8px;
- text-align:left;
+td { padding: 3px 7px 3px 9px; height: 15px; box-sizing: border-box; }
+
+.stackNumber {
+    width: 2em;
+    padding: 3px 0;
+    text-align: center;
 }
 
-li {
-list-style-image:url(SourceArrow.png);
+.variable {
+    width: 12em;
+}
+
+.column th.scrollCorner {
+    width: 15px;
+    padding: 0;
+    border-right: none;
 }
 
+.column th {
+    background: url(glossyHeader.png) repeat-x;
+    border-right: 1px solid #d9d9d9;
+    height: 15px;
+    box-sizing: border-box; 
+    border-bottom: 1px solid #aaa;
+    font-weight: normal;
+    vertical-align: middle;
+    padding: 0 8px;
+    text-align: left;
+    -webkit-user-select: none;
+}
index d2c55d1ac2050739c090b4d29492426f2bb9f630..f2454001aa83bdc74a43463ad4639d145cd0e31c 100644 (file)
@@ -41,17 +41,26 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 </div>
 <div id="main">
 <div id="info">
-<div id="console">
 <div id="leftPane">
+<div id="stackframe">
+<table id="stackframeTableHeader">
+<tr class="column"><th class="stackNumber">#</th><th>Function</th><th class="scrollCorner"></th></tr>
+</table>
+<div id="stackframeBody">
 <div class="infoBackground"></div>
+<table id="stackframeTable"></table>
+</div>
+</div>
 </div>
 <div id="rightPane">
 <div id="infoDivider"></div>
 <div id="variables">
-<div class="infoBackground"></div>
-<table id="variablesTable">
-<tr class="column"><th>Variable</th><th>Value</th></tr>
+<table id="variablesTableHeader">
+<tr class="column"><th class="variable">Variable</th><th>Value</th><th class="scrollCorner"></th></tr>
 </table>
+<div id="variablesBody">
+<div class="infoBackground"></div>
+<table id="variablesTable"></table>
 </div>
 </div>
 </div>
index da774d3e115d7694981f5d65f106b515c85dc20b..92d70e9a9ecb6cddc5d4ea898fe13d5712867e88 100644 (file)
@@ -29,6 +29,7 @@
 var sourceFiles = new Array();
 var currentSourceId = -1;
 var currentRow = null;
+var currentStack = null;
 var previousFiles = new Array();
 var nextFiles = new Array();
 
@@ -142,6 +143,12 @@ function resume()
         currentRow = null;
     }
 
+    if (currentStack) {
+        var stackframeTable = document.getElementById("stackframeTable");
+        stackframeTable.innerHTML = ""; // clear the content
+        currentStack = null;
+    }
+
     DebuggerDocument.resume();
 }
 
@@ -365,6 +372,39 @@ function navFileNext(element)
     loadSource(lastSource, false);
 }
 
+function updateFunctionStack()
+{
+    var stackframeTable = document.getElementById("stackframeTable");
+    stackframeTable.innerHTML = ""; // clear the content
+
+    currentStack = DebuggerDocument.currentFunctionStack();
+    for(var i = 0; i < currentStack.length; i++) {
+        var tr = document.createElement("tr");
+        var td = document.createElement("td");
+        td.className = "stackNumber";
+        td.innerText = i;
+        tr.appendChild(td);
+
+        td = document.createElement("td");
+        td.innerText = currentStack[i];
+        tr.appendChild(td);
+
+        stackframeTable.appendChild(tr);
+    }
+
+    var tr = document.createElement("tr");
+    var td = document.createElement("td");
+    td.className = "stackNumber";
+    td.innerText = i;
+    tr.appendChild(td);
+
+    td = document.createElement("td");
+    td.innerText = "Global";
+    tr.appendChild(td);
+
+    stackframeTable.appendChild(tr);
+}
+
 function loadSource(sourceId,manageNavLists)
 {
     if (!sourceFiles[sourceId])
@@ -467,6 +507,8 @@ function willExecuteStatement(sourceId,line)
         if (sourceFiles[sourceId].element.firstChild.childNodes.length < line)
             return;
 
+        updateFunctionStack();
+
         currentRow = sourceFiles[sourceId].element.firstChild.childNodes.item(line - 1);
         addStyleClass(currentRow, "current");