Changeset 208885 in webkit


Ignore:
Timestamp:
Nov 18, 2016, 10:57:17 AM (9 years ago)
Author:
Joseph Pecoraro
Message:

Web Inspector: Generator functions should have a displayable name when shown in stack traces
https://bugs.webkit.org/show_bug.cgi?id=164844
<rdar://problem/29300697>

Reviewed by Yusuke Suzuki.

JSTests:

  • stress/generator-function-name.js:

Add another test now that we name the inner generator function
that we do not break the lexical resolution of names.

Source/JavaScriptCore:

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createGeneratorFunctionBody):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createGeneratorFunctionBody):
New way to create a generator function with an inferred name.

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):

  • parser/Parser.h:

Pass on the name of the generator wrapper function so we can
use it on the inner generator function.

LayoutTests:

  • inspector/debugger/js-stacktrace-expected.txt:
  • inspector/debugger/js-stacktrace.html:

Add a test case for console.trace() / Error stack inside of generators.
Modernize the test to reduce redundency and get nicer output.

Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r208867 r208885  
     12016-11-18  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Generator functions should have a displayable name when shown in stack traces
     4        https://bugs.webkit.org/show_bug.cgi?id=164844
     5        <rdar://problem/29300697>
     6
     7        Reviewed by Yusuke Suzuki.
     8
     9        * stress/generator-function-name.js:
     10        Add another test now that we name the inner generator function
     11        that we do not break the lexical resolution of names.
     12
    1132016-11-17  Yusuke Suzuki  <utatane.tea@gmail.com>
    214
  • trunk/JSTests/stress/generator-function-name.js

    r192937 r208885  
    1111var g = ok();
    1212shouldBe(g.next().value, ok);
     13
     14function* generator2(factory)
     15{
     16    shouldBe(generator2, factory);
     17};
     18
     19generator2(generator2).next();
  • trunk/LayoutTests/ChangeLog

    r208876 r208885  
     12016-11-18  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Generator functions should have a displayable name when shown in stack traces
     4        https://bugs.webkit.org/show_bug.cgi?id=164844
     5        <rdar://problem/29300697>
     6
     7        Reviewed by Yusuke Suzuki.
     8
     9        * inspector/debugger/js-stacktrace-expected.txt:
     10        * inspector/debugger/js-stacktrace.html:
     11        Add a test case for console.trace() / Error stack inside of generators.
     12        Modernize the test to reduce redundency and get nicer output.
     13
    1142016-11-17  Sam Weinig  <sam@webkit.org>
    215
  • trunk/LayoutTests/inspector/debugger/js-stacktrace-expected.txt

    r200533 r208885  
    1 Test that the inspector can parse the stack trace format used by JSC for Error instances and console.trace.
     1Tests that we can parse the stack trace format used by JavaScriptCore and the contents of Error / console.trace stack traces.
     2
     3
     4== Running test suite: ConsoleTraceAndJavaScriptStackTrace
     5-- Running test case: ConsoleTraceAndJavaScriptStackTrace.BasicError
    26
    37console.trace():
    48[
    59    {
    6         "lineNumber": 15,
    7         "columnNumber": 22,
    8         "functionName": "typeError",
    9         "nativeCode": false,
    10         "programCode": false
    11     },
    12     {
    13         "lineNumber": 6,
     10        "lineNumber": 10,
     11        "columnNumber": 22,
     12        "functionName": "typeError",
     13        "nativeCode": false,
     14        "programCode": false
     15    },
     16    {
     17        "lineNumber": 16,
    1418        "columnNumber": 21,
    15         "functionName": "typeErrorWrap",
    16         "nativeCode": false,
    17         "programCode": false
    18     },
    19     {
    20         "lineNumber": 0,
    21         "columnNumber": 14,
     19        "functionName": "triggerTypeError",
     20        "nativeCode": false,
     21        "programCode": false
     22    },
     23    {
     24        "lineNumber": 0,
     25        "columnNumber": 17,
    2226        "functionName": "Global Code",
    2327        "nativeCode": false,
     
    3135        "functionName": "typeError",
    3236        "url": "/inspector/debugger/js-stacktrace.html",
    33         "lineNumber": 14,
     37        "lineNumber": 9,
    3438        "columnNumber": 30
    3539    },
    3640    {
    37         "functionName": "typeErrorWrap",
    38         "url": "/inspector/debugger/js-stacktrace.html",
    39         "lineNumber": 7,
     41        "functionName": "triggerTypeError",
     42        "url": "/inspector/debugger/js-stacktrace.html",
     43        "lineNumber": 17,
    4044        "columnNumber": 21
    4145    },
     
    4852]
    4953
     54-- Running test case: ConsoleTraceAndJavaScriptStackTrace.ErrorInNativeCall
     55
    5056console.trace():
    5157[
    5258    {
    53         "lineNumber": 15,
     59        "lineNumber": 10,
    5460        "columnNumber": 22,
    5561        "functionName": "typeError",
     
    6571    },
    6672    {
    67         "lineNumber": 22,
     73        "lineNumber": 20,
    6874        "columnNumber": 20,
    69         "functionName": "testWithNativeCallInBetween",
    70         "nativeCode": false,
    71         "programCode": false
    72     },
    73     {
    74         "lineNumber": 0,
    75         "columnNumber": 28,
     75        "functionName": "triggerTypeErrorWithNativeCallInBetween",
     76        "nativeCode": false,
     77        "programCode": false
     78    },
     79    {
     80        "lineNumber": 0,
     81        "columnNumber": 40,
    7682        "functionName": "Global Code",
    7783        "nativeCode": false,
     
    8591        "functionName": "typeError",
    8692        "url": "/inspector/debugger/js-stacktrace.html",
    87         "lineNumber": 14,
     93        "lineNumber": 9,
    8894        "columnNumber": 30
    8995    },
     
    95101    },
    96102    {
    97         "functionName": "testWithNativeCallInBetween",
    98         "url": "/inspector/debugger/js-stacktrace.html",
    99         "lineNumber": 23,
     103        "functionName": "triggerTypeErrorWithNativeCallInBetween",
     104        "url": "/inspector/debugger/js-stacktrace.html",
     105        "lineNumber": 21,
    100106        "columnNumber": 20
    101107    },
     
    108114]
    109115
     116-- Running test case: ConsoleTraceAndJavaScriptStackTrace.ErrorInAnonymousFunction
     117
    110118Error object:
    111119[
     
    113121        "functionName": "",
    114122        "url": "/inspector/debugger/js-stacktrace.html",
    115         "lineNumber": 31,
     123        "lineNumber": 29,
    116124        "columnNumber": 33
    117125    },
     
    119127        "functionName": "global code",
    120128        "url": "/inspector/debugger/js-stacktrace.html",
    121         "lineNumber": 35,
     129        "lineNumber": 33,
    122130        "columnNumber": 3
    123131    }
    124132]
    125133
     134-- Running test case: ConsoleTraceAndJavaScriptStackTrace.ErrorInGenerator
     135
     136console.trace():
     137[
     138    {
     139        "lineNumber": 10,
     140        "columnNumber": 22,
     141        "functionName": "typeError",
     142        "nativeCode": false,
     143        "programCode": false
     144    },
     145    {
     146        "lineNumber": 43,
     147        "columnNumber": 20,
     148        "functionName": "generator2",
     149        "nativeCode": false,
     150        "programCode": false
     151    },
     152    {
     153        "lineNumber": null,
     154        "columnNumber": null,
     155        "functionName": "generatorResume",
     156        "nativeCode": true,
     157        "programCode": false
     158    },
     159    {
     160        "lineNumber": 39,
     161        "columnNumber": 12,
     162        "functionName": "generator1",
     163        "nativeCode": false,
     164        "programCode": false
     165    },
     166    {
     167        "lineNumber": null,
     168        "columnNumber": null,
     169        "functionName": "generatorResume",
     170        "nativeCode": true,
     171        "programCode": false
     172    },
     173    {
     174        "lineNumber": 47,
     175        "columnNumber": 29,
     176        "functionName": "triggerGeneratorError",
     177        "nativeCode": false,
     178        "programCode": false
     179    },
     180    {
     181        "lineNumber": 0,
     182        "columnNumber": 22,
     183        "functionName": "Global Code",
     184        "nativeCode": false,
     185        "programCode": true
     186    }
     187]
     188
     189Error object:
     190[
     191    {
     192        "functionName": "typeError",
     193        "url": "/inspector/debugger/js-stacktrace.html",
     194        "lineNumber": 9,
     195        "columnNumber": 30
     196    },
     197    {
     198        "functionName": "generator2",
     199        "url": "/inspector/debugger/js-stacktrace.html",
     200        "lineNumber": 44,
     201        "columnNumber": 20
     202    },
     203    {
     204        "functionName": "generatorResume",
     205        "url": "[native code]",
     206        "lineNumber": 0,
     207        "columnNumber": 0
     208    },
     209    {
     210        "functionName": "generator1",
     211        "url": "/inspector/debugger/js-stacktrace.html",
     212        "lineNumber": 40,
     213        "columnNumber": 12
     214    },
     215    {
     216        "functionName": "generatorResume",
     217        "url": "[native code]",
     218        "lineNumber": 0,
     219        "columnNumber": 0
     220    },
     221    {
     222        "functionName": "triggerGeneratorError",
     223        "url": "/inspector/debugger/js-stacktrace.html",
     224        "lineNumber": 48,
     225        "columnNumber": 29
     226    },
     227    {
     228        "functionName": "global code",
     229        "url": "",
     230        "lineNumber": 0,
     231        "columnNumber": 0
     232    }
     233]
     234
  • trunk/LayoutTests/inspector/debugger/js-stacktrace.html

    r200533 r208885  
     1<!DOCTYPE html>
    12<html>
    23<head>
    34<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
    45<script>
    5 function typeErrorWrap()
    6 {
    7     return typeError();
    8 }
    9 
    10 function typeError()
    11 {
    12     var object = {};
     6function typeError() {
     7    let object = {};
    138    try {
    149        object.propertyDoesnt.exist;
     
    1914}
    2015
    21 function testWithNativeCallInBetween()
    22 {
     16function triggerTypeError() {
     17    return typeError();
     18}
     19
     20function triggerTypeErrorWithNativeCallInBetween() {
    2321    return [42].map(typeError)[0];
    2422}
    2523
    26 var _anonymousFunctionError = null;
     24let _anonymousFunctionError = null;
    2725
    2826(function() {
    29     var object = {};
     27    let object = {};
    3028    try {
    3129        object.methodDoesntExist();
     
    3937}
    4038
     39function* generator1() {
     40    yield* generator2();
     41}
     42
     43function* generator2() {
     44    yield typeError();
     45}
     46
     47function triggerGeneratorError() {
     48    return generator1().next().value;
     49}
    4150
    4251function test()
    4352{
    44     WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, function(event) {
     53    function stripFilePaths(stackTrace) {
     54        for (let frame of stackTrace) {
     55            if (typeof frame.url === "string")
     56                frame.url = frame.url.replace(/^.+?LayoutTests/, "");
     57        }
     58        return stackTrace;
     59    }
     60
     61    function stripCallFramesAfterEval(stackTrace) {
     62        for (let i = 0; i < stackTrace.length; ++i) {
     63            let frame = stackTrace[i];
     64            if (frame.programCode)
     65                return stackTrace.slice(0, i + 1);
     66        }
     67        return stackTrace;
     68    }
     69
     70    function stripPayloadAfterGlobalCode(stackTrace) {
     71        for (let i = 0; i < stackTrace.length; ++i) {
     72            let frame = stackTrace[i];
     73            if (frame.functionName === "global code")
     74                return stackTrace.slice(0, i + 1);
     75        }
     76        return stackTrace;
     77    }
     78
     79    WebInspector.logManager.addEventListener(WebInspector.LogManager.Event.MessageAdded, (event) => {
    4580        InspectorTest.log("\nconsole.trace():");
    4681
    47         var stackTrace = [];
    48         var callFramesBeforeEval = stripCallFramesAfterEval(event.data.message.stackTrace.callFrames);
    49         for (var callFrame of callFramesBeforeEval) {
    50             var lineNumber = callFrame.sourceCodeLocation ? callFrame.sourceCodeLocation.lineNumber : null;
    51             var columnNumber = callFrame.sourceCodeLocation ? callFrame.sourceCodeLocation.columnNumber : null;
     82        let stackTrace = [];
     83        let callFramesBeforeEval = stripCallFramesAfterEval(event.data.message.stackTrace.callFrames);
     84        for (let callFrame of callFramesBeforeEval) {
     85            let lineNumber = callFrame.sourceCodeLocation ? callFrame.sourceCodeLocation.lineNumber : null;
     86            let columnNumber = callFrame.sourceCodeLocation ? callFrame.sourceCodeLocation.columnNumber : null;
    5287            stackTrace.push({
    5388                lineNumber: lineNumber,
     
    6196        InspectorTest.log(JSON.stringify(stackTrace, null, 4));
    6297    });
     98   
    6399
    64     InspectorTest.evaluateInPage("typeErrorWrap()", function(error, result) {
    65         InspectorTest.log("\nError object:");
     100    let suite = InspectorTest.createAsyncSuite("ConsoleTraceAndJavaScriptStackTrace");
    66101
    67         if (error)
    68             InspectorTest.log(error);
     102    function addTestCase({name, expression}) {
     103        suite.addTestCase({
     104            name,
     105            test(resolve, reject) {
     106                InspectorTest.evaluateInPage(expression, (error, result) => {
     107                    InspectorTest.assert(!error, error);
     108                    InspectorTest.log("\nError object:");
     109                    let stackTrace = stripFilePaths(stripPayloadAfterGlobalCode(WebInspector.StackTrace._parseStackTrace(result.value)));
     110                    InspectorTest.log(JSON.stringify(stackTrace, null, 4));
     111                    resolve();
     112                });
     113            }
     114        });
     115    }
    69116
    70         var stackTrace = stripPayloadAfterGlobalCode(WebInspector.StackTrace._parseStackTrace(result.value));
    71         stackTrace = stripFilePaths(stackTrace);
    72 
    73         InspectorTest.log(JSON.stringify(stackTrace, null, 4));
    74         InspectorTest.completeTest();
     117    addTestCase({
     118        name: "ConsoleTraceAndJavaScriptStackTrace.BasicError",
     119        expression: "triggerTypeError()",
    75120    });
    76121
    77     InspectorTest.evaluateInPage("testWithNativeCallInBetween()", function(error, result) {
    78         InspectorTest.log("\nError object:");
    79 
    80         if (error)
    81             InspectorTest.log(error);
    82 
    83         var stackTrace = stripPayloadAfterGlobalCode(WebInspector.StackTrace._parseStackTrace(result.value));
    84         stackTrace = stripFilePaths(stackTrace);
    85 
    86         InspectorTest.log(JSON.stringify(stackTrace, null, 4));
    87         InspectorTest.completeTest();
     122    addTestCase({
     123        name: "ConsoleTraceAndJavaScriptStackTrace.ErrorInNativeCall",
     124        expression: "triggerTypeErrorWithNativeCallInBetween()",
    88125    });
    89126
    90     InspectorTest.evaluateInPage("getAnonymousFunctionError()", function(error, result) {
    91         InspectorTest.log("\nError object:");
    92 
    93         if (error)
    94             InspectorTest.log(error);
    95 
    96         var stackTrace = stripPayloadAfterGlobalCode(WebInspector.StackTrace._parseStackTrace(result.value));
    97         stackTrace = stripFilePaths(stackTrace);
    98 
    99         InspectorTest.log(JSON.stringify(stackTrace, null, 4));
    100         InspectorTest.completeTest();
     127    addTestCase({
     128        name: "ConsoleTraceAndJavaScriptStackTrace.ErrorInAnonymousFunction",
     129        expression: "getAnonymousFunctionError()",
    101130    });
    102131
    103     function stripFilePaths(stackTrace)
    104     {
    105         for (var frame of stackTrace) {
    106             if (typeof frame.url === "string")
    107                 frame.url = frame.url.replace(/^.+?LayoutTests/, "");
    108         }
    109         return stackTrace;
    110     }
     132    addTestCase({
     133        name: "ConsoleTraceAndJavaScriptStackTrace.ErrorInGenerator",
     134        expression: "triggerGeneratorError()",
     135    });
    111136
    112     function stripCallFramesAfterEval(stackTrace)
    113     {
    114         var index = 0;
    115         for (var frame of stackTrace) {
    116             index++;
    117             if (frame.programCode)
    118                 break;
    119         }
    120         return stackTrace.slice(0, index);
    121     }
    122 
    123     function stripPayloadAfterGlobalCode(payload)
    124     {
    125         var index = 0;
    126         for (var frame of payload) {
    127             index++;
    128             if (frame.functionName === "global code")
    129                 break;
    130         }
    131         return payload.slice(0, index);
    132     }
     137    suite.runTestCasesAndFinish();
    133138}
    134139</script>
    135140</head>
    136141<body onload="runTest()">
    137 <p>
    138 Test that the inspector can parse the stack trace format used by JSC for Error instances and console.trace.<br>
    139 </p>
     142<p>Tests that we can parse the stack trace format used by JavaScriptCore and the contents of Error / console.trace stack traces.</p>
    140143</body>
    141144</html>
  • trunk/Source/JavaScriptCore/ChangeLog

    r208878 r208885  
     12016-11-18  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Generator functions should have a displayable name when shown in stack traces
     4        https://bugs.webkit.org/show_bug.cgi?id=164844
     5        <rdar://problem/29300697>
     6
     7        Reviewed by Yusuke Suzuki.
     8
     9        * parser/SyntaxChecker.h:
     10        (JSC::SyntaxChecker::createGeneratorFunctionBody):
     11        * parser/ASTBuilder.h:
     12        (JSC::ASTBuilder::createGeneratorFunctionBody):
     13        New way to create a generator function with an inferred name.
     14
     15        * parser/Parser.cpp:
     16        (JSC::Parser<LexerType>::parseInner):
     17        (JSC::Parser<LexerType>::parseGeneratorFunctionSourceElements):
     18        * parser/Parser.h:
     19        Pass on the name of the generator wrapper function so we can
     20        use it on the inner generator function.
     21
    1222016-11-17  Ryosuke Niwa  <rniwa@webkit.org>
    223
  • trunk/Source/JavaScriptCore/parser/ASTBuilder.h

    r207228 r208885  
    390390    }
    391391
     392    ExpressionNode* createGeneratorFunctionBody(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo, const Identifier& name)
     393    {
     394        FuncExprNode* result = static_cast<FuncExprNode*>(createFunctionExpr(location, functionInfo));
     395        if (!name.isNull())
     396            result->metadata()->setInferredName(name);
     397        return result;
     398    }
     399
    392400    ExpressionNode* createAsyncFunctionBody(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo, SourceParseMode parseMode)
    393401    {
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r208843 r208885  
    291291            sourceElements = parseModuleSourceElements(context, parseMode);
    292292        else if (parseMode == SourceParseMode::GeneratorWrapperFunctionMode)
    293             sourceElements = parseGeneratorFunctionSourceElements(context, CheckForStrictMode);
     293            sourceElements = parseGeneratorFunctionSourceElements(context, calleeName, CheckForStrictMode);
    294294        else
    295295            sourceElements = parseSourceElements(context, CheckForStrictMode);
     
    505505
    506506template <typename LexerType>
    507 template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseGeneratorFunctionSourceElements(TreeBuilder& context, SourceElementsMode mode)
     507template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseGeneratorFunctionSourceElements(TreeBuilder& context, const Identifier& name, SourceElementsMode mode)
    508508{
    509509    auto sourceElements = context.createSourceElements();
     
    538538    info.parametersStartColumn = startColumn;
    539539
    540     auto functionExpr = context.createFunctionExpr(startLocation, info);
     540    auto functionExpr = context.createGeneratorFunctionBody(startLocation, info, name);
    541541    auto statement = context.createExprStatement(startLocation, functionExpr, start, m_lastTokenEndPosition.line);
    542542    context.appendStatement(sourceElements, statement);
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r208097 r208885  
    14691469
    14701470    template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode);
    1471     template <class TreeBuilder> TreeSourceElements parseGeneratorFunctionSourceElements(TreeBuilder&, SourceElementsMode);
     1471    template <class TreeBuilder> TreeSourceElements parseGeneratorFunctionSourceElements(TreeBuilder&, const Identifier& name, SourceElementsMode);
    14721472    template <class TreeBuilder> TreeSourceElements parseAsyncFunctionSourceElements(TreeBuilder&, SourceParseMode, bool isArrowFunctionBodyExpression, SourceElementsMode);
    14731473    template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r207228 r208885  
    185185    ClassExpression createClassExpr(const JSTokenLocation&, const ParserClassInfo<SyntaxChecker>&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
    186186    ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
     187    ExpressionType createGeneratorFunctionBody(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&, const Identifier&) { return FunctionExpr; }
    187188    ExpressionType createAsyncFunctionBody(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
    188189    int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, SuperBinding, unsigned, int, SourceParseMode, bool, InnerArrowFunctionCodeFeatures = NoInnerArrowFunctionFeatures) { return FunctionBodyResult; }
Note: See TracChangeset for help on using the changeset viewer.