Title: [127243] trunk/Source/WebCore
Revision
127243
Author
[email protected]
Date
2012-08-31 02:56:10 -0700 (Fri, 31 Aug 2012)

Log Message

Web Inspector: [WebGL] Link WebGL calls to the source code where it was made
https://bugs.webkit.org/show_bug.cgi?id=95426

Patch by Andrey Adaikin <[email protected]> on 2012-08-31
Reviewed by Vsevolod Vlasov.

Save a stack trace for every call we capture and report to the frontend sourceURL,lineNumber,columnNumber were the call was made from.
Right now, this will work only with V8.

* inspector/InjectedScriptExterns.js:
(CallSite.prototype.getFileName):
(CallSite.prototype.getLineNumber):
(CallSite.prototype.getColumnNumber):
* inspector/InjectedScriptWebGLModuleSource.js:
(.):
* inspector/Inspector.json:
* inspector/front-end/WebGLProfileView.js:
(WebInspector.WebGLProfileView):
(WebInspector.WebGLProfileView.prototype._showTraceLog):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (127242 => 127243)


--- trunk/Source/WebCore/ChangeLog	2012-08-31 09:43:27 UTC (rev 127242)
+++ trunk/Source/WebCore/ChangeLog	2012-08-31 09:56:10 UTC (rev 127243)
@@ -1,3 +1,24 @@
+2012-08-31  Andrey Adaikin  <[email protected]>
+
+        Web Inspector: [WebGL] Link WebGL calls to the source code where it was made
+        https://bugs.webkit.org/show_bug.cgi?id=95426
+
+        Reviewed by Vsevolod Vlasov.
+
+        Save a stack trace for every call we capture and report to the frontend sourceURL,lineNumber,columnNumber were the call was made from.
+        Right now, this will work only with V8.
+
+        * inspector/InjectedScriptExterns.js:
+        (CallSite.prototype.getFileName):
+        (CallSite.prototype.getLineNumber):
+        (CallSite.prototype.getColumnNumber):
+        * inspector/InjectedScriptWebGLModuleSource.js:
+        (.):
+        * inspector/Inspector.json:
+        * inspector/front-end/WebGLProfileView.js:
+        (WebInspector.WebGLProfileView):
+        (WebInspector.WebGLProfileView.prototype._showTraceLog):
+
 2012-08-31  Patrick Dubroy  <[email protected]>
 
         Web Inspector: Add high-DPI images for status bar glyphs

Modified: trunk/Source/WebCore/inspector/InjectedScriptExterns.js (127242 => 127243)


--- trunk/Source/WebCore/inspector/InjectedScriptExterns.js	2012-08-31 09:43:27 UTC (rev 127242)
+++ trunk/Source/WebCore/inspector/InjectedScriptExterns.js	2012-08-31 09:56:10 UTC (rev 127243)
@@ -114,3 +114,23 @@
 }
 
 var InspectorBackend = { };
+
+// http://code.google.com/p/v8/wiki/_javascript_StackTraceApi
+/**
+ * @constructor
+ */
+function CallSite()
+{
+}
+/**
+ * @return {string}
+ */
+CallSite.prototype.getFileName = function() { }
+/**
+ * @return {number}
+ */
+CallSite.prototype.getLineNumber = function() { }
+/**
+ * @return {number}
+ */
+CallSite.prototype.getColumnNumber = function() { }

Modified: trunk/Source/WebCore/inspector/InjectedScriptWebGLModuleSource.js (127242 => 127243)


--- trunk/Source/WebCore/inspector/InjectedScriptWebGLModuleSource.js	2012-08-31 09:43:27 UTC (rev 127242)
+++ trunk/Source/WebCore/inspector/InjectedScriptWebGLModuleSource.js	2012-08-31 09:56:10 UTC (rev 127243)
@@ -132,8 +132,97 @@
 }
 
 /**
+ * @interface
+ */
+function StackTrace()
+{
+}
+
+StackTrace.prototype = {
+    /**
+     * @param {number} index
+     * @return {{sourceURL: string, lineNumber: number, columnNumber: number}}
+     */
+    callFrame: function(index)
+    {
+    }
+}
+
+/**
+ * @param {number=} stackTraceLimit
+ * @param {Function=} topMostFunctionToIgnore
+ * @return {StackTrace}
+ */
+StackTrace.create = function(stackTraceLimit, topMostFunctionToIgnore)
+{
+    if (typeof Error.captureStackTrace === "function")
+        return new StackTraceV8(stackTraceLimit, topMostFunctionToIgnore || arguments.callee);
+    // FIXME: Support JSC, and maybe other browsers.
+    return null;
+}
+
+/**
  * @constructor
+ * @implements {StackTrace}
+ * @param {number=} stackTraceLimit
+ * @param {Function=} topMostFunctionToIgnore
+ * @see http://code.google.com/p/v8/wiki/_javascript_StackTraceApi
  */
+function StackTraceV8(stackTraceLimit, topMostFunctionToIgnore)
+{
+    StackTrace.call(this);
+    var oldStackTraceLimit = Error.stackTraceLimit;
+    if (typeof stackTraceLimit === "number")
+        Error.stackTraceLimit = stackTraceLimit;
+
+    this._error = /** @type {{stack: Array}} */ {};
+    Error.captureStackTrace(this._error, topMostFunctionToIgnore || arguments.callee);
+
+    Error.stackTraceLimit = oldStackTraceLimit;
+}
+
+StackTraceV8.prototype = {
+    /**
+     * @override
+     * @param {number} index
+     * @return {{sourceURL: string, lineNumber: number, columnNumber: number}}
+     */
+    callFrame: function(index)
+    {
+        if (!this._stackTrace)
+            this._prepareStackTrace();
+        return this._stackTrace[index];
+    },
+
+    _prepareStackTrace: function()
+    {
+        var oldPrepareStackTrace = Error.prepareStackTrace;
+        /**
+         * @param {Object} error
+         * @param {Array.<CallSite>} structuredStackTrace
+         * @return {Array.<{sourceURL: string, lineNumber: number, columnNumber: number}>}
+         */
+        Error.prepareStackTrace = function(error, structuredStackTrace)
+        {
+            return structuredStackTrace.map(function(callSite) {
+                return {
+                    sourceURL: callSite.getFileName(),
+                    lineNumber: callSite.getLineNumber(),
+                    columnNumber: callSite.getColumnNumber()
+                };
+            });
+        }
+        this._stackTrace = this._error.stack;
+        Error.prepareStackTrace = oldPrepareStackTrace;
+        delete this._error; // No longer needed, free memory.
+    }
+}
+
+StackTraceV8.prototype.__proto__ = StackTrace.prototype;
+
+/**
+ * @constructor
+ */
 function Cache()
 {
     this.reset();
@@ -190,13 +279,15 @@
  * @param {string} functionName
  * @param {Array|Arguments} args
  * @param {Resource|*=} result
+ * @param {StackTrace=} stackTrace
  */
-function Call(thisObject, functionName, args, result)
+function Call(thisObject, functionName, args, result, stackTrace)
 {
     this._thisObject = thisObject;
     this._functionName = functionName;
     this._args = Array.prototype.slice.call(args, 0);
     this._result = result;
+    this._stackTrace = stackTrace || null;
 }
 
 Call.prototype = {
@@ -232,6 +323,22 @@
         return this._result;
     },
 
+    /**
+     * @return {StackTrace}
+     */
+    stackTrace: function()
+    {
+        return this._stackTrace;
+    },
+
+    /**
+     * @param {StackTrace} stackTrace
+     */
+    setStackTrace: function(stackTrace)
+    {
+        this._stackTrace = stackTrace;
+    },
+
     freeze: function()
     {
         if (this._freezed)
@@ -256,7 +363,7 @@
         var args = this._args.map(function(obj) {
             return Resource.toReplayable(obj, cache);
         });
-        return new ReplayableCall(thisObject, this._functionName, args, result);
+        return new ReplayableCall(thisObject, this._functionName, args, result, this._stackTrace);
     },
 
     /**
@@ -283,6 +390,7 @@
         this._functionName = replayableCall.functionName();
         this._args = replayArgs;
         this._result = replayResult;
+        this._stackTrace = replayableCall.stackTrace();
         this._freezed = true;
         return this;
     }
@@ -294,13 +402,15 @@
  * @param {string} functionName
  * @param {Array.<ReplayableResource|*>} args
  * @param {ReplayableResource|*} result
+ * @param {StackTrace} stackTrace
  */
-function ReplayableCall(thisObject, functionName, args, result)
+function ReplayableCall(thisObject, functionName, args, result, stackTrace)
 {
     this._thisObject = thisObject;
     this._functionName = functionName;
     this._args = args;
     this._result = result;
+    this._stackTrace = stackTrace;
 }
 
 ReplayableCall.prototype = {
@@ -337,6 +447,14 @@
     },
 
     /**
+     * @return {StackTrace}
+     */
+    stackTrace: function()
+    {
+        return this._stackTrace;
+    },
+
+    /**
      * @param {Cache} cache
      * @return {Call}
      */
@@ -1349,8 +1467,11 @@
                 manager.captureArguments(resource, arguments);
             var wrapFunction = new WebGLRenderingContextResource.WrapFunction(originalObject, originalFunction, functionName, arguments);
             customWrapFunction.apply(wrapFunction, arguments);
-            if (manager)
-                manager.reportCall(wrapFunction.call());
+            if (manager && manager.capturing()) {
+                var call = wrapFunction.call();
+                call.setStackTrace(StackTrace.create(1, arguments.callee));
+                manager.reportCall(call);
+            }
             return wrapFunction.result();
         };
     },
@@ -1371,7 +1492,8 @@
                 return originalFunction.apply(originalObject, arguments);
             manager.captureArguments(resource, arguments);
             var result = originalFunction.apply(originalObject, arguments);
-            var call = new Call(resource, functionName, arguments, result);
+            var stackTrace = StackTrace.create(1, arguments.callee);
+            var call = new Call(resource, functionName, arguments, result, stackTrace);
             manager.reportCall(call);
             return result;
         };
@@ -1776,9 +1898,21 @@
         var calls = traceLog.replayableCalls();
         for (var i = 0, n = calls.length; i < n; ++i) {
             var call = calls[i];
-            result.calls.push({
-                functionName: call.functionName() + "(" + call.args().join(", ") + ") => " + call.result()
+            var args = call.args().map(function(argument) {
+                return argument + "";
             });
+            var stackTrace = call.stackTrace();
+            var callFrame = stackTrace ? stackTrace.callFrame(0) || {} : {};
+            var traceLogItem = {
+                functionName: call.functionName(),
+                arguments: args,
+                sourceURL: callFrame.sourceURL,
+                lineNumber: callFrame.lineNumber,
+                columnNumber: callFrame.columnNumber
+            };
+            if (call.result())
+                traceLogItem.result = call.result() + "";
+            result.calls.push(traceLogItem);
         }
         return result;
     },

Modified: trunk/Source/WebCore/inspector/Inspector.json (127242 => 127243)


--- trunk/Source/WebCore/inspector/Inspector.json	2012-08-31 09:43:27 UTC (rev 127242)
+++ trunk/Source/WebCore/inspector/Inspector.json	2012-08-31 09:56:10 UTC (rev 127243)
@@ -3149,7 +3149,12 @@
                 "id": "Call",
                 "type": "object",
                 "properties": [
-                    { "name": "functionName", "type": "string" }
+                    { "name": "functionName", "type": "string" },
+                    { "name": "arguments", "type": "array", "items": { "type": "string" } },
+                    { "name": "result", "type": "string", "optional": true },
+                    { "name": "sourceURL", "type": "string", "optional": true },
+                    { "name": "lineNumber", "type": "integer", "optional": true },
+                    { "name": "columnNumber", "type": "integer", "optional": true }
                 ]
             },
             {
@@ -3157,7 +3162,7 @@
                 "type": "object",
                 "properties": [
                     { "name": "id", "$ref": "TraceLogId" },
-                    { "name": "calls", "type": "array", "items": { "$ref": "Call" }}
+                    { "name": "calls", "type": "array", "items": { "$ref": "Call" } }
                 ]
             }
         ],

Modified: trunk/Source/WebCore/inspector/front-end/WebGLProfileView.js (127242 => 127243)


--- trunk/Source/WebCore/inspector/front-end/WebGLProfileView.js	2012-08-31 09:43:27 UTC (rev 127242)
+++ trunk/Source/WebCore/inspector/front-end/WebGLProfileView.js	2012-08-31 09:56:10 UTC (rev 127243)
@@ -55,12 +55,15 @@
     this._debugInfoElement = document.createElement("div");
     replayImageContainer.appendChild(this._debugInfoElement);
 
+    this._linkifier = new WebInspector.Linkifier();
+
     this._showTraceLog();
 }
 
 WebInspector.WebGLProfileView.prototype = {
     dispose: function()
     {
+        this._linkifier.reset();
         WebGLAgent.dropTraceLog(this._profile.traceLogId());
     },
 
@@ -105,7 +108,21 @@
                 var traceLogItem = document.createElement("div");
                 traceLogItem.traceLogId = traceLog.id;
                 traceLogItem.stepNo = i;
-                traceLogItem.textContent = "(" + (i+1) + ") " + call.functionName;
+                traceLogItem.appendChild(document.createTextNode("(" + (i+1) + ") "));
+
+                if (call.sourceURL) {
+                    // FIXME(62725): stack trace line/column numbers are one-based.
+                    var lineNumber = Math.max(0, call.lineNumber - 1) || 0;
+                    var columnNumber = Math.max(0, call.columnNumber - 1) || 0;
+                    var linkElement = this._linkifier.linkifyLocation(call.sourceURL, lineNumber, columnNumber);
+                    linkElement.textContent = call.functionName;
+                    traceLogItem.appendChild(linkElement);
+                } else
+                    traceLogItem.appendChild(document.createTextNode(call.functionName));
+
+                traceLogItem.appendChild(document.createTextNode("(" + call.arguments.join(", ") + ")"));
+                if (typeof call.result !== "undefined")
+                    traceLogItem.appendChild(document.createTextNode(" => " + call.result));
                 this._traceLogElement.appendChild(traceLogItem);
             }
         }
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to