Home | History | Annotate | Download | only in v8
      1 /*
      2  * Copyright (C) 2010 Google 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 (function () {
     32 
     33 var DebuggerScript = {};
     34 
     35 DebuggerScript.PauseOnExceptionsState = {
     36     DontPauseOnExceptions : 0,
     37     PauseOnAllExceptions : 1,
     38     PauseOnUncaughtExceptions: 2
     39 };
     40 
     41 DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.DontPauseOnExceptions;
     42 Debug.clearBreakOnException();
     43 Debug.clearBreakOnUncaughtException();
     44 
     45 DebuggerScript.getAfterCompileScript = function(eventData)
     46 {
     47     return DebuggerScript._formatScript(eventData.script_.script_);
     48 }
     49 
     50 DebuggerScript.getWorkerScripts = function()
     51 {
     52     var result = [];
     53     var scripts = Debug.scripts();
     54     for (var i = 0; i < scripts.length; ++i) {
     55         var script = scripts[i];
     56         // Workers don't share same V8 heap now so there is no need to complicate stuff with
     57         // the context id like we do to discriminate between scripts from different pages.
     58         // However we need to filter out v8 native scripts.
     59         if (script.context_data && script.context_data === "worker")
     60             result.push(DebuggerScript._formatScript(script));
     61     }
     62     return result;
     63 }
     64 
     65 DebuggerScript.getScripts = function(contextData)
     66 {
     67     var result = [];
     68 
     69     if (!contextData)
     70         return result;
     71     var comma = contextData.indexOf(",");
     72     if (comma === -1)
     73         return result;
     74     // Context data is a string in the following format:
     75     // ("page"|"injected")","<page id>
     76     var idSuffix = contextData.substring(comma); // including the comma
     77 
     78     var scripts = Debug.scripts();
     79     for (var i = 0; i < scripts.length; ++i) {
     80         var script = scripts[i];
     81         if (script.context_data && script.context_data.lastIndexOf(idSuffix) != -1)
     82             result.push(DebuggerScript._formatScript(script));
     83     }
     84     return result;
     85 }
     86 
     87 DebuggerScript._formatScript = function(script)
     88 {
     89     return {
     90         id: script.id,
     91         name: script.nameOrSourceURL(),
     92         source: script.source,
     93         lineOffset: script.line_offset,
     94         columnOffset: script.column_offset,
     95         isContentScript: !!script.context_data && script.context_data.indexOf("injected") == 0
     96     };
     97 }
     98 
     99 DebuggerScript.setBreakpoint = function(execState, args)
    100 {
    101     var breakId = Debug.setScriptBreakPointById(args.sourceID, args.lineNumber, args.columnNumber, args.condition);
    102 
    103     var locations = Debug.findBreakPointActualLocations(breakId);
    104     if (!locations.length)
    105         return undefined;
    106     args.lineNumber = locations[0].line;
    107     args.columnNumber = locations[0].column;
    108     return breakId.toString();
    109 }
    110 
    111 DebuggerScript.removeBreakpoint = function(execState, args)
    112 {
    113     Debug.findBreakPoint(args.breakpointId, true);
    114 }
    115 
    116 DebuggerScript.pauseOnExceptionsState = function()
    117 {
    118     return DebuggerScript._pauseOnExceptionsState;
    119 }
    120 
    121 DebuggerScript.setPauseOnExceptionsState = function(newState)
    122 {
    123     DebuggerScript._pauseOnExceptionsState = newState;
    124 
    125     if (DebuggerScript.PauseOnExceptionsState.PauseOnAllExceptions === newState)
    126         Debug.setBreakOnException();
    127     else
    128         Debug.clearBreakOnException();
    129 
    130     if (DebuggerScript.PauseOnExceptionsState.PauseOnUncaughtExceptions === newState)
    131         Debug.setBreakOnUncaughtException();
    132     else
    133         Debug.clearBreakOnUncaughtException();
    134 }
    135 
    136 DebuggerScript.currentCallFrame = function(execState, args)
    137 {
    138     var frameCount = execState.frameCount();
    139     if (frameCount === 0)
    140         return undefined;
    141 
    142     var topFrame;
    143     for (var i = frameCount - 1; i >= 0; i--) {
    144         var frameMirror = execState.frame(i);
    145         topFrame = DebuggerScript._frameMirrorToJSCallFrame(frameMirror, topFrame);
    146     }
    147     return topFrame;
    148 }
    149 
    150 DebuggerScript.stepIntoStatement = function(execState)
    151 {
    152     execState.prepareStep(Debug.StepAction.StepIn, 1);
    153 }
    154 
    155 DebuggerScript.stepOverStatement = function(execState)
    156 {
    157     execState.prepareStep(Debug.StepAction.StepNext, 1);
    158 }
    159 
    160 DebuggerScript.stepOutOfFunction = function(execState)
    161 {
    162     execState.prepareStep(Debug.StepAction.StepOut, 1);
    163 }
    164 
    165 DebuggerScript.editScriptSource = function(scriptId, newSource)
    166 {
    167     var scripts = Debug.scripts();
    168     var scriptToEdit = null;
    169     for (var i = 0; i < scripts.length; i++) {
    170         if (scripts[i].id == scriptId) {
    171             scriptToEdit = scripts[i];
    172             break;
    173         }
    174     }
    175     if (!scriptToEdit)
    176         throw("Script not found");
    177 
    178     var changeLog = [];
    179     Debug.LiveEdit.SetScriptSource(scriptToEdit, newSource, false, changeLog);
    180     return scriptToEdit.source;
    181 }
    182 
    183 DebuggerScript.clearBreakpoints = function(execState, args)
    184 {
    185     Debug.clearAllBreakPoints();
    186 }
    187 
    188 DebuggerScript.setBreakpointsActivated = function(execState, args)
    189 {
    190     Debug.debuggerFlags().breakPointsActive.setValue(args.enabled);
    191 }
    192 
    193 DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame)
    194 {
    195     // Get function name.
    196     var func;
    197     try {
    198         func = frameMirror.func();
    199     } catch(e) {
    200     }
    201     var functionName;
    202     if (func)
    203         functionName = func.name() || func.inferredName();
    204 
    205     // Get script ID.
    206     var script = func.script();
    207     var sourceID = script && script.id();
    208 
    209     // Get location.
    210     var location  = frameMirror.sourceLocation();
    211 
    212     // Get this object.
    213     var thisObject = frameMirror.details_.receiver();
    214 
    215     // Get scope chain array in format: [<scope type>, <scope object>, <scope type>, <scope object>,...]
    216     var scopeChain = [];
    217     var scopeType = [];
    218     for (var i = 0; i < frameMirror.scopeCount(); i++) {
    219         var scopeMirror = frameMirror.scope(i);
    220         var scopeObjectMirror = scopeMirror.scopeObject();
    221 
    222         var scopeObject;
    223         switch (scopeMirror.scopeType()) {
    224         case ScopeType.Local:
    225         case ScopeType.Closure:
    226             // For transient objects we create a "persistent" copy that contains
    227             // the same properties.
    228             scopeObject = {};
    229             // Reset scope object prototype to null so that the proto properties
    230             // don't appear in the local scope section.
    231             scopeObject.__proto__ = null;
    232             var properties = scopeObjectMirror.properties();
    233             for (var j = 0; j < properties.length; j++) {
    234                 var name = properties[j].name();
    235                 if (name.charAt(0) === ".")
    236                     continue; // Skip internal variables like ".arguments"
    237                 scopeObject[name] = properties[j].value_;
    238             }
    239             break;
    240         case ScopeType.Global:
    241         case ScopeType.With:
    242         case ScopeType.Catch:
    243             scopeObject = scopeMirror.details_.object();
    244             break;
    245         }
    246 
    247         scopeType.push(scopeMirror.scopeType());
    248         scopeChain.push(scopeObject);
    249     }
    250 
    251     function evaluate(expression) {
    252         return frameMirror.evaluate(expression, false).value();
    253     }
    254 
    255     return {
    256         "sourceID": sourceID,
    257         "line": location.line,
    258         "column": location.column,
    259         "functionName": functionName,
    260         "thisObject": thisObject,
    261         "scopeChain": scopeChain,
    262         "scopeType": scopeType,
    263         "evaluate": evaluate,
    264         "caller": callerFrame
    265     };
    266 }
    267 
    268 return DebuggerScript;
    269 })();
    270