Changeset 237054 in webkit


Ignore:
Timestamp:
Oct 11, 2018, 4:43:58 PM (7 years ago)
Author:
[email protected]
Message:

[JSC] JSC should have "parseFunction" to optimize Function constructor
https://bugs.webkit.org/show_bug.cgi?id=190340

Reviewed by Mark Lam.

JSTests:

This patch fixes the line number of syntax errors raised by the Function constructor,
since we now parse the final code only once. And we no longer use block statement
for Function constructor's parsing.

  • ChakraCore/test/Function/FuncBodyES5.baseline-jsc:
  • stress/function-cache-with-parameters-end-position.js: Added.

(shouldBe):
(shouldThrow):
(i.anonymous):

  • stress/function-constructor-name.js: Added.

(shouldBe):
(GeneratorFunction):
(AsyncFunction.async):
(AsyncGeneratorFunction.async):
(anonymous):
(async.anonymous):

  • test262/expectations.yaml:

LayoutTests/imported/w3c:

  • web-platform-tests/html/webappapis/scripting/events/inline-event-handler-ordering-expected.txt:
  • web-platform-tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-late-expected.txt:
  • web-platform-tests/html/webappapis/scripting/processing-model-2/compile-error-in-attribute-expected.txt:
  • web-platform-tests/html/webappapis/scripting/processing-model-2/compile-error-in-body-onerror-expected.txt:

Source/JavaScriptCore:

The current Function constructor is suboptimal. We parse the piece of the same code three times to meet
the spec requirement. (1) check parameters syntax, (2) check body syntax, and (3) parse the entire function.
And to parse 1-3 correctly, we create two strings, the parameters and the entire function. This operation
is really costly and ideally we should meet the above requirement by the one time parsing.

To meet the above requirement, we add a special function for Parser, parseSingleFunction. This function
takes std::optional<int> functionConstructorParametersEndPosition and check this end position is correct in the parser.
For example, if we run the code,

Function('/*', '*/){')

According to the spec, this should produce '/*' parameter string and '*/){' body string. And parameter
string should be syntax-checked by the parser, and raise the error since it is incorrect. Instead of doing
that, in our implementation, we first create the entire string.

function anonymous(/*) {

*/){

}

And we parse it. At that time, we also pass the end position of the parameters to the parser. In the above case,
the position of the `function anonymous(/*)' <> is passed. And in the parser, we check that the last token
offset of the parameters is the given end position. This check allows us to raise the error correctly to the
above example while we parse the entire function only once. And we do not need to create two strings too.

This improves the performance of the Function constructor significantly. And web-tooling-benchmark/uglify-js is
significantly sped up (28.2%).

Before:

uglify-js: 2.94 runs/s

After:

uglify-js: 3.77 runs/s

  • bytecode/UnlinkedFunctionExecutable.cpp:

(JSC::UnlinkedFunctionExecutable::fromGlobalCode):

  • bytecode/UnlinkedFunctionExecutable.h:
  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseSingleFunction):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseAsyncFunctionDeclaration):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parsePropertyMethod):
(JSC::Parser<LexerType>::parseGetterSetter):
(JSC::Parser<LexerType>::parseFunctionExpression):
(JSC::Parser<LexerType>::parseAsyncFunctionExpression):
(JSC::Parser<LexerType>::parseArrowFunctionExpression):

  • parser/Parser.h:

(JSC::Parser<LexerType>::parse):
(JSC::parse):
(JSC::parseFunctionForFunctionConstructor):

  • parser/ParserModes.h:
  • parser/ParserTokens.h:

(JSC::JSTextPosition::JSTextPosition):
(JSC::JSTokenLocation::JSTokenLocation): Deleted.

  • parser/SourceCodeKey.h:

(JSC::SourceCodeKey::SourceCodeKey):
(JSC::SourceCodeKey::operator== const):

  • runtime/CodeCache.cpp:

(JSC::CodeCache::getUnlinkedGlobalCodeBlock):
(JSC::CodeCache::getUnlinkedGlobalFunctionExecutable):

  • runtime/CodeCache.h:
  • runtime/FunctionConstructor.cpp:

(JSC::constructFunctionSkippingEvalEnabledCheck):

  • runtime/FunctionExecutable.cpp:

(JSC::FunctionExecutable::fromGlobalCode):

  • runtime/FunctionExecutable.h:

LayoutTests:

  • fast/dom/attribute-event-listener-errors-expected.txt:
  • fast/events/attribute-listener-deletion-crash-expected.txt:
  • fast/events/window-onerror-syntax-error-in-attr-expected.txt:
  • js/dom/invalid-syntax-for-function-expected.txt:
  • js/dom/script-start-end-locations-expected.txt:
Location:
trunk
Files:
2 added
27 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChakraCore/test/Function/FuncBodyES5.baseline-jsc

    r218845 r237054  
    1010PASS: 9: new Function succeeded as expected
    1111PASS: 10: new Function succeeded as expected
    12 PASS: 100: new Function failed as expected. SyntaxError: Unexpected token '{'. Expected ')' to end a compound expression.
    13 PASS: 100: new Function failed as expected. SyntaxError: Unexpected token '{'. Expected ')' to end a compound expression.
    14 PASS: 101: new Function failed as expected. SyntaxError: Unexpected keyword 'function'. Expected ')' to end a compound expression.
    15 PASS: 102: new Function failed as expected. SyntaxError: Unexpected keyword 'function'. Expected ')' to end a compound expression.
    16 PASS: 103: new Function failed as expected. SyntaxError: Unexpected keyword 'function'. Expected ')' to end a compound expression.
    17 PASS: 104: new Function failed as expected. SyntaxError: Unexpected token ';'. Expected ')' to end a compound expression.
    18 PASS: 105: new Function failed as expected. SyntaxError: Unexpected token ';'. Expected ')' to end a compound expression.
     12PASS: 100: new Function failed as expected. SyntaxError: Parser error
     13PASS: 100: new Function failed as expected. SyntaxError: Parser error
     14PASS: 101: new Function failed as expected. SyntaxError: Parser error
     15PASS: 102: new Function failed as expected. SyntaxError: Parameters should match arguments offered as parameters in Function constructor.
     16PASS: 103: new Function failed as expected. SyntaxError: Parser error
     17PASS: 104: new Function failed as expected. SyntaxError: Parameters should match arguments offered as parameters in Function constructor.
     18PASS: 105: new Function failed as expected. SyntaxError: Parser error
    1919PASS: 200: new Function failed as expected. SyntaxError: Unexpected token ','. Expected a parameter pattern or a ')' in parameter list.
    2020PASS: 200: new Function failed as expected. SyntaxError: Unexpected token ','. Expected a parameter pattern or a ')' in parameter list.
  • trunk/JSTests/ChangeLog

    r237000 r237054  
     12018-10-08  Yusuke Suzuki  <[email protected]>
     2
     3        [JSC] JSC should have "parseFunction" to optimize Function constructor
     4        https://bugs.webkit.org/show_bug.cgi?id=190340
     5
     6        Reviewed by Mark Lam.
     7
     8        This patch fixes the line number of syntax errors raised by the Function constructor,
     9        since we now parse the final code only once. And we no longer use block statement
     10        for Function constructor's parsing.
     11
     12        * ChakraCore/test/Function/FuncBodyES5.baseline-jsc:
     13        * stress/function-cache-with-parameters-end-position.js: Added.
     14        (shouldBe):
     15        (shouldThrow):
     16        (i.anonymous):
     17        * stress/function-constructor-name.js: Added.
     18        (shouldBe):
     19        (GeneratorFunction):
     20        (AsyncFunction.async):
     21        (AsyncGeneratorFunction.async):
     22        (anonymous):
     23        (async.anonymous):
     24        * test262/expectations.yaml:
     25
    1262018-10-10  Guillaume Emont  <[email protected]>
    227
  • trunk/JSTests/test262/expectations.yaml

    r235882 r237054  
    901901  strict mode: "ReferenceError: Can't find variable: verifyNotEnumerable"
    902902test/built-ins/Function/prototype/toString/AsyncFunction.js:
    903   default: "SyntaxError: Unexpected token '}'. Expected a ')' or a ',' after a parameter declaration."
    904   strict mode: "SyntaxError: Unexpected token '}'. Expected a ')' or a ',' after a parameter declaration."
     903  default: "SyntaxError: Unexpected token ';'. Expected a ')' or a ',' after a parameter declaration."
     904  strict mode: "SyntaxError: Unexpected token ';'. Expected a ')' or a ',' after a parameter declaration."
    905905test/built-ins/Function/prototype/toString/Function.js:
    906   default: "SyntaxError: Unexpected token '}'. Expected a ')' or a ',' after a parameter declaration."
    907   strict mode: "SyntaxError: Unexpected token '}'. Expected a ')' or a ',' after a parameter declaration."
     906  default: "SyntaxError: Unexpected token ';'. Expected a ')' or a ',' after a parameter declaration."
     907  strict mode: "SyntaxError: Unexpected token ';'. Expected a ')' or a ',' after a parameter declaration."
    908908test/built-ins/Function/prototype/toString/GeneratorFunction.js:
    909   default: "SyntaxError: Unexpected token '}'. Expected a ')' or a ',' after a parameter declaration."
    910   strict mode: "SyntaxError: Unexpected token '}'. Expected a ')' or a ',' after a parameter declaration."
     909  default: "SyntaxError: Unexpected keyword 'yield'. Expected a ')' or a ',' after a parameter declaration."
     910  strict mode: "SyntaxError: Unexpected keyword 'yield'. Expected a ')' or a ',' after a parameter declaration."
    911911test/built-ins/Function/prototype/toString/async-arrow-function.js:
    912912  default: "Test262Error: Conforms to NativeFunction Syntax: 'async ( /* b */ a /* c */ , /* d */ b /* e */ ) /* f */ => /* g */ { /* h */ ; /* i */ }'.(async /* a */ ( /* b */ a /* c */ , /* d */ b /* e */ ) /* f */ => /* g */ { /* h */ ; /* i */ })"
  • trunk/LayoutTests/ChangeLog

    r237048 r237054  
     12018-10-08  Yusuke Suzuki  <[email protected]>
     2
     3        [JSC] JSC should have "parseFunction" to optimize Function constructor
     4        https://bugs.webkit.org/show_bug.cgi?id=190340
     5
     6        Reviewed by Mark Lam.
     7
     8        * fast/dom/attribute-event-listener-errors-expected.txt:
     9        * fast/events/attribute-listener-deletion-crash-expected.txt:
     10        * fast/events/window-onerror-syntax-error-in-attr-expected.txt:
     11        * js/dom/invalid-syntax-for-function-expected.txt:
     12        * js/dom/script-start-end-locations-expected.txt:
     13
    1142018-10-11  Thibault Saunier  <[email protected]>
    215
  • trunk/LayoutTests/fast/dom/attribute-event-listener-errors-expected.txt

    r218845 r237054  
    11CONSOLE MESSAGE: line 4: ReferenceError: Can't find variable: error
    2 CONSOLE MESSAGE: line 9: SyntaxError: Invalid character: '@'
     2CONSOLE MESSAGE: line 5: SyntaxError: Invalid character: '@'
    33This test verifies that an attribute event listener error shows the right line number even if the attribute contains newlines.
    44 
  • trunk/LayoutTests/fast/events/attribute-listener-deletion-crash-expected.txt

    r218845 r237054  
    1 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    2 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    3 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    4 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    5 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    6 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    7 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    8 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    9 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    10 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    11 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    12 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    13 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    14 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    15 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    16 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    17 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    18 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    19 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
    20 CONSOLE MESSAGE: line 2: SyntaxError: Unexpected token '|'
     1CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     2CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     3CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     4CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     5CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     6CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     7CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     8CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     9CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     10CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     11CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     12CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     13CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     14CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     15CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     16CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     17CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     18CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     19CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
     20CONSOLE MESSAGE: line 1: SyntaxError: Unexpected token '|'
    2121PASS
  • trunk/LayoutTests/fast/events/window-onerror-syntax-error-in-attr-expected.txt

    r218845 r237054  
    11Test that window.onerror is called on window object when there is a syntax error in attribute handler. Bug 70991.
    22
    3 Main frame window.onerror: SyntaxError: Unexpected token '%' at window-onerror-syntax-error-in-attr.html:11:38 SyntaxError: Unexpected token '%'
    4 Main frame window.onerror: SyntaxError: Unexpected token '%' at window-onerror-syntax-error-in-attr.html:37:38 SyntaxError: Unexpected token '%'
    5 Main frame window.onerror: SyntaxError: Unexpected token '%' at window-onerror-syntax-error-in-attr.html:37:14 SyntaxError: Unexpected token '%'
     3Main frame window.onerror: SyntaxError: Unexpected token '%' at window-onerror-syntax-error-in-attr.html:10:38 SyntaxError: Unexpected token '%'
     4Main frame window.onerror: SyntaxError: Unexpected token '%' at window-onerror-syntax-error-in-attr.html:36:38 SyntaxError: Unexpected token '%'
     5Main frame window.onerror: SyntaxError: Unexpected token '%' at window-onerror-syntax-error-in-attr.html:36:14 SyntaxError: Unexpected token '%'
    66Button 1 Button 2 Button 3
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r237002 r237054  
     12018-10-08  Yusuke Suzuki  <[email protected]>
     2
     3        [JSC] JSC should have "parseFunction" to optimize Function constructor
     4        https://bugs.webkit.org/show_bug.cgi?id=190340
     5
     6        Reviewed by Mark Lam.
     7
     8        * web-platform-tests/html/webappapis/scripting/events/inline-event-handler-ordering-expected.txt:
     9        * web-platform-tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-late-expected.txt:
     10        * web-platform-tests/html/webappapis/scripting/processing-model-2/compile-error-in-attribute-expected.txt:
     11        * web-platform-tests/html/webappapis/scripting/processing-model-2/compile-error-in-body-onerror-expected.txt:
     12
    1132018-10-10  Chris Dumez  <[email protected]>
    214
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/webappapis/scripting/events/inline-event-handler-ordering-expected.txt

    r218845 r237054  
    11CONSOLE MESSAGE: line 19: SyntaxError: Unexpected token '}'
    2 CONSOLE MESSAGE: line 54: SyntaxError: Unexpected token '}'
     2CONSOLE MESSAGE: line 52: SyntaxError: Unexpected token '}'
    33
    44PASS Inline event handlers retain their ordering when invalid and force-compiled
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-late-expected.txt

    r218845 r237054  
    1 CONSOLE MESSAGE: line 26: SyntaxError: Unexpected token '}'. Expected ')' to end a compound expression.
    2 CONSOLE MESSAGE: line 21: SyntaxError: Unexpected token '}'. Expected ')' to end a compound expression.
     1CONSOLE MESSAGE: line 24: SyntaxError: Parser error
     2CONSOLE MESSAGE: line 21: SyntaxError: Parser error
    33
    44FAIL Invalid uncompiled raw handlers should only be compiled when about to call them. assert_array_equals: lengths differ, expected 3 got 4
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/webappapis/scripting/processing-model-2/compile-error-in-attribute-expected.txt

    r218845 r237054  
    1 CONSOLE MESSAGE: line 26: SyntaxError: Unexpected token ')'
     1CONSOLE MESSAGE: line 24: SyntaxError: Unexpected end of script
    22
    33PASS window.onerror - compile error in attribute
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/webappapis/scripting/processing-model-2/compile-error-in-body-onerror-expected.txt

    r218845 r237054  
    11CONSOLE MESSAGE: line 19: SyntaxError: Unexpected token ')'
    2 CONSOLE MESSAGE: line 18: SyntaxError: Unexpected token ')'
     2CONSOLE MESSAGE: line 16: SyntaxError: Unexpected end of script
    33
    44PASS window.onerror - compile error in <body onerror>
  • trunk/LayoutTests/js/dom/invalid-syntax-for-function-expected.txt

    r218845 r237054  
    1 CONSOLE MESSAGE: line 2: SyntaxError: Invalid character: '#'
     1CONSOLE MESSAGE: line 1: SyntaxError: Invalid character: '#'
    22This test ensures we don't crash when we are given garbage for an attribute expecting a function.
    33https://bugs.webkit.org/show_bug.cgi?id=19025
  • trunk/LayoutTests/js/dom/script-start-end-locations-expected.txt

    r186959 r237054  
    244244
    245245  new Function Object:
    246 function "anonymous" { 1:20 - 2:228 }
     246function "anonymous" { 1:19 - 2:228 }
    247247function "nf1a" { 2:57 - 2:219 }
    248248function "nf1b" { 2:87 - 2:209 }
    249249function "nf1c" { 2:117 - 2:199 }
    250250eval { 1:1 - 1:56 }
    251 function "anonymous" { 1:20 - 18:8 }
     251function "anonymous" { 1:19 - 18:8 }
    252252function "nf2a" { 5:18 - 16:5 }
    253253function "nf2b" { 7:22 - 14:9 }
    254254function "nf2c" { 9:26 - 12:13 }
    255255eval { 1:1 - 1:56 }
    256 function "anonymous" { 1:20 - 2:228 }
     256function "anonymous" { 1:19 - 2:228 }
    257257function "nf1a" { 2:57 - 2:219 }
    258258function "nf1b" { 2:87 - 2:209 }
    259259function "nf1c" { 2:117 - 2:199 }
    260260eval { 1:1 - 1:56 }
    261 function "anonymous" { 1:20 - 2:237 }
     261function "anonymous" { 1:19 - 2:237 }
    262262function "nfi1a" { 2:58 - 2:227 }
    263263function "nfi1b" { 2:90 - 2:216 }
    264264function "nfi1c" { 2:122 - 2:205 }
    265265eval { 1:1 - 1:56 }
    266 function "anonymous" { 1:20 - 18:8 }
     266function "anonymous" { 1:19 - 18:8 }
    267267function "nf2a" { 5:18 - 16:5 }
    268268function "nf2b" { 7:22 - 14:9 }
    269269function "nf2c" { 9:26 - 12:13 }
    270270eval { 1:1 - 1:56 }
    271 function "anonymous" { 1:20 - 18:9 }
     271function "anonymous" { 1:19 - 18:9 }
    272272function "nfi2a" { 5:19 - 16:5 }
    273273function "nfi2b" { 7:23 - 14:9 }
  • trunk/Source/JavaScriptCore/ChangeLog

    r237051 r237054  
     12018-10-08  Yusuke Suzuki  <[email protected]>
     2
     3        [JSC] JSC should have "parseFunction" to optimize Function constructor
     4        https://bugs.webkit.org/show_bug.cgi?id=190340
     5
     6        Reviewed by Mark Lam.
     7
     8        The current Function constructor is suboptimal. We parse the piece of the same code three times to meet
     9        the spec requirement. (1) check parameters syntax, (2) check body syntax, and (3) parse the entire function.
     10        And to parse 1-3 correctly, we create two strings, the parameters and the entire function. This operation
     11        is really costly and ideally we should meet the above requirement by the one time parsing.
     12
     13        To meet the above requirement, we add a special function for Parser, parseSingleFunction. This function
     14        takes `std::optional<int> functionConstructorParametersEndPosition` and check this end position is correct in the parser.
     15        For example, if we run the code,
     16
     17            Function('/*', '*/){')
     18
     19        According to the spec, this should produce '/*' parameter string and '*/){' body string. And parameter
     20        string should be syntax-checked by the parser, and raise the error since it is incorrect. Instead of doing
     21        that, in our implementation, we first create the entire string.
     22
     23            function anonymous(/*) {
     24                */){
     25            }
     26
     27        And we parse it. At that time, we also pass the end position of the parameters to the parser. In the above case,
     28        the position of the `function anonymous(/*)' <> is passed. And in the parser, we check that the last token
     29        offset of the parameters is the given end position. This check allows us to raise the error correctly to the
     30        above example while we parse the entire function only once. And we do not need to create two strings too.
     31
     32        This improves the performance of the Function constructor significantly. And web-tooling-benchmark/uglify-js is
     33        significantly sped up (28.2%).
     34
     35        Before:
     36            uglify-js:  2.94 runs/s
     37        After:
     38            uglify-js:  3.77 runs/s
     39
     40        * bytecode/UnlinkedFunctionExecutable.cpp:
     41        (JSC::UnlinkedFunctionExecutable::fromGlobalCode):
     42        * bytecode/UnlinkedFunctionExecutable.h:
     43        * parser/Parser.cpp:
     44        (JSC::Parser<LexerType>::parseInner):
     45        (JSC::Parser<LexerType>::parseSingleFunction):
     46        (JSC::Parser<LexerType>::parseFunctionInfo):
     47        (JSC::Parser<LexerType>::parseFunctionDeclaration):
     48        (JSC::Parser<LexerType>::parseAsyncFunctionDeclaration):
     49        (JSC::Parser<LexerType>::parseClass):
     50        (JSC::Parser<LexerType>::parsePropertyMethod):
     51        (JSC::Parser<LexerType>::parseGetterSetter):
     52        (JSC::Parser<LexerType>::parseFunctionExpression):
     53        (JSC::Parser<LexerType>::parseAsyncFunctionExpression):
     54        (JSC::Parser<LexerType>::parseArrowFunctionExpression):
     55        * parser/Parser.h:
     56        (JSC::Parser<LexerType>::parse):
     57        (JSC::parse):
     58        (JSC::parseFunctionForFunctionConstructor):
     59        * parser/ParserModes.h:
     60        * parser/ParserTokens.h:
     61        (JSC::JSTextPosition::JSTextPosition):
     62        (JSC::JSTokenLocation::JSTokenLocation): Deleted.
     63        * parser/SourceCodeKey.h:
     64        (JSC::SourceCodeKey::SourceCodeKey):
     65        (JSC::SourceCodeKey::operator== const):
     66        * runtime/CodeCache.cpp:
     67        (JSC::CodeCache::getUnlinkedGlobalCodeBlock):
     68        (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable):
     69        * runtime/CodeCache.h:
     70        * runtime/FunctionConstructor.cpp:
     71        (JSC::constructFunctionSkippingEvalEnabledCheck):
     72        * runtime/FunctionExecutable.cpp:
     73        (JSC::FunctionExecutable::fromGlobalCode):
     74        * runtime/FunctionExecutable.h:
     75
    1762018-10-11  Ross Kirsling  <[email protected]>
    277
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp

    r233039 r237054  
    175175UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(
    176176    const Identifier& name, ExecState& exec, const SourceCode& source,
    177     JSObject*& exception, int overrideLineNumber)
     177    JSObject*& exception, int overrideLineNumber, std::optional<int> functionConstructorParametersEndPosition)
    178178{
    179179    ParserError error;
     
    182182    CodeCache* codeCache = vm.codeCache();
    183183    DebuggerMode debuggerMode = globalObject.hasInteractiveDebugger() ? DebuggerOn : DebuggerOff;
    184     UnlinkedFunctionExecutable* executable = codeCache->getUnlinkedGlobalFunctionExecutable(vm, name, source, debuggerMode, error);
     184    UnlinkedFunctionExecutable* executable = codeCache->getUnlinkedGlobalFunctionExecutable(vm, name, source, debuggerMode, functionConstructorParametersEndPosition, error);
    185185
    186186    if (globalObject.hasDebugger())
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h

    r233039 r237054  
    108108    static UnlinkedFunctionExecutable* fromGlobalCode(
    109109        const Identifier&, ExecState&, const SourceCode&, JSObject*& exception,
    110         int overrideLineNumber);
     110        int overrideLineNumber, std::optional<int> functionConstructorParametersEndPosition);
    111111
    112112    JS_EXPORT_PRIVATE FunctionExecutable* link(VM&, const SourceCode& parentSource, std::optional<int> overrideLineNumber = std::nullopt, Intrinsic = NoIntrinsic);
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r233855 r237054  
    196196
    197197template <typename LexerType>
    198 String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode)
     198String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, std::optional<int> functionConstructorParametersEndPosition)
    199199{
    200200    String parseError = String();
     
    240240        else if (isAsyncGeneratorWrapperParseMode(parseMode))
    241241            sourceElements = parseAsyncGeneratorFunctionSourceElements(context, parseMode, isArrowFunctionBodyExpression, CheckForStrictMode);
     242        else if (parsingContext == ParsingContext::FunctionConstructor)
     243            sourceElements = parseSingleFunction(context, functionConstructorParametersEndPosition);
    242244        else
    243245            sourceElements = parseSourceElements(context, CheckForStrictMode);
     
    612614    return sourceElements;
    613615}
     616
     617template <typename LexerType>
     618template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseSingleFunction(TreeBuilder& context, std::optional<int> functionConstructorParametersEndPosition)
     619{
     620    TreeSourceElements sourceElements = context.createSourceElements();
     621    TreeStatement statement = 0;
     622    switch (m_token.m_type) {
     623    case FUNCTION:
     624        statement = parseFunctionDeclaration(context, ExportType::NotExported, DeclarationDefaultContext::Standard, functionConstructorParametersEndPosition);
     625        break;
     626    case IDENT:
     627        if (*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped) {
     628            next();
     629            failIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Cannot parse the async function");
     630            statement = parseAsyncFunctionDeclaration(context, ExportType::NotExported, DeclarationDefaultContext::Standard, functionConstructorParametersEndPosition);
     631            break;
     632        }
     633        FALLTHROUGH;
     634    default:
     635        failDueToUnexpectedToken();
     636        break;
     637    }
     638
     639    if (statement) {
     640        context.setEndOffset(statement, m_lastTokenEndPosition.offset);
     641        context.appendStatement(sourceElements, statement);
     642    }
     643
     644    propagateError();
     645    return sourceElements;
     646}
     647
    614648   
    615649template <typename LexerType>
     
    22652299
    22662300template <typename LexerType>
    2267 template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionNameRequirements requirements, SourceParseMode mode, bool nameIsInContainingScope, ConstructorKind constructorKind, SuperBinding expectedSuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& functionInfo, FunctionDefinitionType functionDefinitionType)
     2301template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionNameRequirements requirements, SourceParseMode mode, bool nameIsInContainingScope, ConstructorKind constructorKind, SuperBinding expectedSuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& functionInfo, FunctionDefinitionType functionDefinitionType, std::optional<int> functionConstructorParametersEndPosition)
    22682302{
    22692303    RELEASE_ASSERT(isFunctionParseMode(mode));
     
    24612495       
    24622496        matchOrFail(OPENBRACE, "Expected an opening '{' at the start of a ", stringForFunctionMode(mode), " body");
     2497
     2498        // If the code is invoked from function constructor, we need to ensure that parameters are only composed by the string offered as parameters.
     2499        if (functionConstructorParametersEndPosition)
     2500            semanticFailIfFalse(lastTokenEndPosition().offset == *functionConstructorParametersEndPosition, "Parameters should match arguments offered as parameters in Function constructor");
    24632501       
    24642502        // BytecodeGenerator emits code to throw TypeError when a class constructor is "call"ed.
     
    25952633
    25962634template <typename LexerType>
    2597 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext)
     2635template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext, std::optional<int> functionConstructorParametersEndPosition)
    25982636{
    25992637    ASSERT(match(FUNCTION));
     
    26322670    }
    26332671
    2634     failIfFalse((parseFunctionInfo(context, requirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this function");
     2672    failIfFalse((parseFunctionInfo(context, requirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration, functionConstructorParametersEndPosition)), "Cannot parse this function");
    26352673    ASSERT(functionInfo.name);
    26362674
     
    26532691
    26542692template <typename LexerType>
    2655 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseAsyncFunctionDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext)
     2693template <class TreeBuilder> TreeStatement Parser<LexerType>::parseAsyncFunctionDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext, std::optional<int> functionConstructorParametersEndPosition)
    26562694{
    26572695    ASSERT(match(FUNCTION));
     
    26902728    }
    26912729
    2692     failIfFalse((parseFunctionInfo(context, requirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this async function");
     2730    failIfFalse((parseFunctionInfo(context, requirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration, functionConstructorParametersEndPosition)), "Cannot parse this async function");
    26932731    failIfFalse(functionInfo.name, "Async function statements must have a name");
    26942732
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r233377 r237054  
    860860};
    861861
    862 enum class ArgumentType {
    863     Normal,
    864     Spread
    865 };
     862enum class ArgumentType { Normal, Spread };
     863enum class ParsingContext { Program, FunctionConstructor, Eval };
    866864
    867865template <typename LexerType>
     
    875873
    876874    template <class ParsedNode>
    877     std::unique_ptr<ParsedNode> parse(ParserError&, const Identifier&, SourceParseMode);
     875    std::unique_ptr<ParsedNode> parse(ParserError&, const Identifier&, SourceParseMode, ParsingContext, std::optional<int> functionConstructorParametersEndPosition = std::nullopt);
    878876
    879877    JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); }
     
    13131311
    13141312    Parser();
    1315     String parseInner(const Identifier&, SourceParseMode);
     1313
     1314    String parseInner(const Identifier&, SourceParseMode, ParsingContext, std::optional<int> functionConstructorParametersEndPosition = std::nullopt);
    13161315
    13171316    void didFinishParsing(SourceElements*, DeclarationStacks::FunctionStack&&, VariableEnvironment&, UniquedStringImplPtrSet&&, CodeFeatures, int);
     
    15251524    template <class TreeBuilder> TreeSourceElements parseAsyncFunctionSourceElements(TreeBuilder&, SourceParseMode, bool isArrowFunctionBodyExpression, SourceElementsMode);
    15261525    template <class TreeBuilder> TreeSourceElements parseAsyncGeneratorFunctionSourceElements(TreeBuilder&, SourceParseMode, bool isArrowFunctionBodyExpression, SourceElementsMode);
     1526    template <class TreeBuilder> TreeSourceElements parseSingleFunction(TreeBuilder&, std::optional<int> functionConstructorParametersEndPosition);
    15271527    template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
    15281528    template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
    15291529    enum class ExportType { Exported, NotExported };
    15301530    template <class TreeBuilder> TreeStatement parseClassDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard);
    1531     template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard);
     1531    template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard, std::optional<int> functionConstructorParametersEndPosition = std::nullopt);
    15321532    template <class TreeBuilder> TreeStatement parseFunctionDeclarationStatement(TreeBuilder&, bool isAsync, bool parentAllowsFunctionDeclarationAsStatement);
    1533     template <class TreeBuilder> TreeStatement parseAsyncFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard);
     1533    template <class TreeBuilder> TreeStatement parseAsyncFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard, std::optional<int> functionConstructorParametersEndPosition = std::nullopt);
    15341534    template <class TreeBuilder> NEVER_INLINE bool maybeParseAsyncFunctionDeclarationStatement(TreeBuilder& context, TreeStatement& result, bool parentAllowsFunctionDeclarationAsStatement);
    15351535    template <class TreeBuilder> TreeStatement parseVariableDeclaration(TreeBuilder&, DeclarationType, ExportType = ExportType::NotExported);
     
    16001600
    16011601    enum class FunctionDefinitionType { Expression, Declaration, Method };
    1602     template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionNameRequirements, SourceParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionDefinitionType);
     1602    template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionNameRequirements, SourceParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionDefinitionType, std::optional<int> functionConstructorParametersEndPosition = std::nullopt);
    16031603   
    16041604    ALWAYS_INLINE bool isArrowFunctionParameters();
     
    18491849template <typename LexerType>
    18501850template <class ParsedNode>
    1851 std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode)
     1851std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, std::optional<int> functionConstructorParametersEndPosition)
    18521852{
    18531853    int errLine;
     
    18661866    unsigned startColumn = m_source->startColumn().zeroBasedInt();
    18671867
    1868     String parseError = parseInner(calleeName, parseMode);
     1868    String parseError = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition);
    18691869
    18701870    int lineNumber = m_lexer->lineNumber();
     
    19611961    if (source.provider()->source().is8Bit()) {
    19621962        Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData);
    1963         result = parser.parse<ParsedNode>(error, name, parseMode);
     1963        result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program);
    19641964        if (positionBeforeLastNewline)
    19651965            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
     
    19741974        ASSERT_WITH_MESSAGE(defaultConstructorKind == ConstructorKind::None, "BuiltinExecutables::createDefaultConstructor should always use a 8-bit string");
    19751975        Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData);
    1976         result = parser.parse<ParsedNode>(error, name, parseMode);
     1976        result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program);
    19771977        if (positionBeforeLastNewline)
    19781978            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
     
    19881988}
    19891989
     1990inline std::unique_ptr<ProgramNode> parseFunctionForFunctionConstructor(VM& vm, const SourceCode& source, ParserError& error, JSTextPosition* positionBeforeLastNewline, std::optional<int> functionConstructorParametersEndPosition)
     1991{
     1992    ASSERT(!source.provider()->source().isNull());
     1993
     1994    MonotonicTime before;
     1995    if (UNLIKELY(Options::reportParseTimes()))
     1996        before = MonotonicTime::now();
     1997
     1998    Identifier name;
     1999    bool isEvalNode = false;
     2000    std::unique_ptr<ProgramNode> result;
     2001    if (source.provider()->source().is8Bit()) {
     2002        Parser<Lexer<LChar>> parser(&vm, source, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, nullptr);
     2003        result = parser.parse<ProgramNode>(error, name, SourceParseMode::ProgramMode, ParsingContext::FunctionConstructor, functionConstructorParametersEndPosition);
     2004        if (positionBeforeLastNewline)
     2005            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
     2006    } else {
     2007        Parser<Lexer<UChar>> parser(&vm, source, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, nullptr);
     2008        result = parser.parse<ProgramNode>(error, name, SourceParseMode::ProgramMode, ParsingContext::FunctionConstructor, functionConstructorParametersEndPosition);
     2009        if (positionBeforeLastNewline)
     2010            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
     2011    }
     2012
     2013    if (UNLIKELY(Options::reportParseTimes())) {
     2014        MonotonicTime after = MonotonicTime::now();
     2015        ParseHash hash(source);
     2016        dataLogLn(result ? "Parsed #" : "Failed to parse #", hash.hashForCall(), "/#", hash.hashForConstruct(), " in ", (after - before).milliseconds(), " ms.");
     2017    }
     2018
     2019    return result;
     2020}
     2021
     2022
    19902023} // namespace
  • trunk/Source/JavaScriptCore/parser/ParserModes.h

    r235662 r237054  
    3434enum class JSParserBuiltinMode { NotBuiltin, Builtin };
    3535enum class JSParserScriptMode { Classic, Module };
    36 enum class JSParserCodeType { Program, Function, Module };
    3736
    3837enum class ConstructorKind { None, Base, Extends };
  • trunk/Source/JavaScriptCore/parser/ParserTokens.h

    r233410 r237054  
    194194    JSTextPosition() = default;
    195195    JSTextPosition(int _line, int _offset, int _lineStartOffset) : line(_line), offset(_offset), lineStartOffset(_lineStartOffset) { }
    196     JSTextPosition(const JSTextPosition& other) : line(other.line), offset(other.offset), lineStartOffset(other.lineStartOffset) { }
    197196
    198197    JSTextPosition operator+(int adjustment) const { return JSTextPosition(line, offset + adjustment, lineStartOffset); }
     
    247246struct JSTokenLocation {
    248247    JSTokenLocation() = default;
    249     JSTokenLocation(const JSTokenLocation& location)
    250     {
    251         line = location.line;
    252         lineStartOffset = location.lineStartOffset;
    253         startOffset = location.startOffset;
    254         endOffset = location.endOffset;
    255     }
    256248
    257249    int line { 0 };
  • trunk/Source/JavaScriptCore/parser/SourceCodeKey.h

    r209220 r237054  
    3030#include "UnlinkedSourceCode.h"
    3131#include <wtf/HashTraits.h>
     32#include <wtf/Hasher.h>
    3233
    3334namespace JSC {
     
    7273class SourceCodeKey {
    7374public:
    74     SourceCodeKey()
    75     {
    76     }
     75    SourceCodeKey() = default;
    7776
    7877    SourceCodeKey(
    7978        const UnlinkedSourceCode& sourceCode, const String& name, SourceCodeType codeType, JSParserStrictMode strictMode,
    8079        JSParserScriptMode scriptMode, DerivedContextType derivedContextType, EvalContextType evalContextType, bool isArrowFunctionContext,
    81         DebuggerMode debuggerMode, TypeProfilerEnabled typeProfilerEnabled, ControlFlowProfilerEnabled controlFlowProfilerEnabled)
     80        DebuggerMode debuggerMode, TypeProfilerEnabled typeProfilerEnabled, ControlFlowProfilerEnabled controlFlowProfilerEnabled, std::optional<int> functionConstructorParametersEndPosition)
    8281            : m_sourceCode(sourceCode)
    8382            , m_name(name)
    8483            , m_flags(codeType, strictMode, scriptMode, derivedContextType, evalContextType, isArrowFunctionContext, debuggerMode, typeProfilerEnabled, controlFlowProfilerEnabled)
    85             , m_hash(sourceCode.hash() ^ m_flags.bits())
     84            , m_functionConstructorParametersEndPosition(functionConstructorParametersEndPosition.value_or(-1))
     85            , m_hash(sourceCode.hash() ^ computeHash(m_flags.bits(), m_functionConstructorParametersEndPosition))
    8686    {
    8787    }
     
    109109            && length() == other.length()
    110110            && m_flags == other.m_flags
     111            && m_functionConstructorParametersEndPosition == other.m_functionConstructorParametersEndPosition
    111112            && m_name == other.m_name
    112113            && string() == other.string();
     
    128129    String m_name;
    129130    SourceCodeFlags m_flags;
    130     unsigned m_hash;
     131    int m_functionConstructorParametersEndPosition { -1 };
     132    unsigned m_hash { 0 };
    131133};
    132134
  • trunk/Source/JavaScriptCore/runtime/CodeCache.cpp

    r231889 r237054  
    5858        derivedContextType, evalContextType, isArrowFunctionContext, debuggerMode,
    5959        vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No,
    60         vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No);
     60        vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No,
     61        std::nullopt);
    6162    SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
    6263    if (cache && Options::useCodeCache()) {
     
    9697}
    9798
    98 UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& vm, const Identifier& name, const SourceCode& source, DebuggerMode debuggerMode, ParserError& error)
     99UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& vm, const Identifier& name, const SourceCode& source, DebuggerMode debuggerMode, std::optional<int> functionConstructorParametersEndPosition, ParserError& error)
    99100{
    100101    bool isArrowFunctionContext = false;
     
    108109        debuggerMode,
    109110        vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No,
    110         vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No);
     111        vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No,
     112        functionConstructorParametersEndPosition);
    111113    SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
    112114    if (cache && Options::useCodeCache()) {
     
    118120
    119121    JSTextPosition positionBeforeLastNewline;
    120     std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
    121         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
    122         JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
    123         error, &positionBeforeLastNewline);
     122    std::unique_ptr<ProgramNode> program = parseFunctionForFunctionConstructor(vm, source, error, &positionBeforeLastNewline, functionConstructorParametersEndPosition);
    124123    if (!program) {
    125124        RELEASE_ASSERT(error.isValid());
     
    128127
    129128    // This function assumes an input string that would result in a single function declaration.
    130     StatementNode* statement = program->singleStatement();
    131     if (UNLIKELY(!statement)) {
    132         JSToken token;
    133         error = ParserError(ParserError::SyntaxError, ParserError::SyntaxErrorIrrecoverable, token, "Parser error", -1);
    134         return nullptr;
    135     }
    136     ASSERT(statement->isBlock());
    137 
    138     StatementNode* funcDecl = static_cast<BlockNode*>(statement)->singleStatement();
     129    StatementNode* funcDecl = program->singleStatement();
    139130    if (UNLIKELY(!funcDecl)) {
    140131        JSToken token;
  • trunk/Source/JavaScriptCore/runtime/CodeCache.h

    r229952 r237054  
    195195    UnlinkedEvalCodeBlock* getUnlinkedEvalCodeBlock(VM&, IndirectEvalExecutable*, const SourceCode&, JSParserStrictMode, DebuggerMode, ParserError&, EvalContextType);
    196196    UnlinkedModuleProgramCodeBlock* getUnlinkedModuleProgramCodeBlock(VM&, ModuleProgramExecutable*, const SourceCode&, DebuggerMode, ParserError&);
    197     UnlinkedFunctionExecutable* getUnlinkedGlobalFunctionExecutable(VM&, const Identifier&, const SourceCode&, DebuggerMode, ParserError&);
     197    UnlinkedFunctionExecutable* getUnlinkedGlobalFunctionExecutable(VM&, const Identifier&, const SourceCode&, DebuggerMode, std::optional<int> functionConstructorParametersEndPosition, ParserError&);
    198198
    199199    void clear() { m_sourceCode.clear(); }
  • trunk/Source/JavaScriptCore/runtime/FunctionConstructor.cpp

    r236804 r237054  
    9595        break;
    9696    case FunctionConstructionMode::AsyncGenerator:
    97         prefix = "{async function*";
     97        prefix = "async function*";
    9898        break;
    9999    }
    100 
    101     auto checkBody = [&] (const String& body) {
    102         // The spec mandates that the body parses a valid function body independent
    103         // of the parameters.
    104         String program = makeString("(", prefix, "(){\n", body, "\n})");
    105         SourceCode source = makeSource(program, sourceOrigin, sourceURL, position);
    106         JSValue exception;
    107         checkSyntax(exec, source, &exception);
    108         if (exception) {
    109             scope.throwException(exec, exception);
    110             return;
    111         }
    112     };
    113100
    114101    // How we stringify functions is sometimes important for web compatibility.
    115102    // See https://bugs.webkit.org/show_bug.cgi?id=24350.
    116103    String program;
     104    std::optional<int> functionConstructorParametersEndPosition = std::nullopt;
    117105    if (args.isEmpty())
    118         program = makeString("{", prefix, functionName.string(), "() {\n\n}}");
     106        program = makeString(prefix, functionName.string(), "() {\n\n}");
    119107    else if (args.size() == 1) {
    120108        auto body = args.at(0).toWTFString(exec);
    121109        RETURN_IF_EXCEPTION(scope, nullptr);
    122         checkBody(body);
    123         RETURN_IF_EXCEPTION(scope, nullptr);
    124         program = makeString("{", prefix, functionName.string(), "() {\n", body, "\n}}");
     110        program = makeString(prefix, functionName.string(), "() {\n", body, "\n}");
    125111    } else {
    126112        StringBuilder builder;
    127         builder.append('{');
    128113        builder.append(prefix);
    129114        builder.append(functionName.string());
     115
    130116        builder.append('(');
    131         StringBuilder parameterBuilder;
    132117        auto viewWithString = args.at(0).toString(exec)->viewWithUnderlyingString(exec);
    133118        RETURN_IF_EXCEPTION(scope, nullptr);
    134         parameterBuilder.append(viewWithString.view);
     119        builder.append(viewWithString.view);
    135120        for (size_t i = 1; i < args.size() - 1; i++) {
    136             parameterBuilder.appendLiteral(", ");
     121            builder.appendLiteral(", ");
    137122            auto viewWithString = args.at(i).toString(exec)->viewWithUnderlyingString(exec);
    138123            RETURN_IF_EXCEPTION(scope, nullptr);
    139             parameterBuilder.append(viewWithString.view);
     124            builder.append(viewWithString.view);
    140125        }
    141         auto body = args.at(args.size() - 1).toWTFString(exec);
     126        functionConstructorParametersEndPosition = builder.length() + 1;
     127        builder.appendLiteral(") {\n");
     128
     129        auto body = args.at(args.size() - 1).toString(exec)->viewWithUnderlyingString(exec);
    142130        RETURN_IF_EXCEPTION(scope, nullptr);
    143 
    144         {
    145             // The spec mandates that the parameters parse as a valid parameter list
    146             // independent of the function body.
    147             String program = tryMakeString("(", prefix, "(", parameterBuilder.toString(), "){\n\n})");
    148             if (UNLIKELY(!program)) {
    149                 throwOutOfMemoryError(exec, scope);
    150                 return nullptr;
    151             }
    152             SourceCode source = makeSource(program, sourceOrigin, sourceURL, position);
    153             JSValue exception;
    154             checkSyntax(exec, source, &exception);
    155             if (exception) {
    156                 scope.throwException(exec, exception);
    157                 return nullptr;
    158             }
    159         }
    160 
    161         builder.append(parameterBuilder);
    162         builder.appendLiteral(") {\n");
    163         checkBody(body);
    164         RETURN_IF_EXCEPTION(scope, nullptr);
    165         builder.append(body);
    166         builder.appendLiteral("\n}}");
     131        builder.append(body.view);
     132        builder.appendLiteral("\n}");
    167133        program = builder.toString();
    168134    }
     
    170136    SourceCode source = makeSource(program, sourceOrigin, sourceURL, position);
    171137    JSObject* exception = nullptr;
    172     FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, *exec, source, exception, overrideLineNumber);
     138    FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, *exec, source, exception, overrideLineNumber, functionConstructorParametersEndPosition);
    173139    if (!function) {
    174140        ASSERT(exception);
  • trunk/Source/JavaScriptCore/runtime/FunctionExecutable.cpp

    r233085 r237054  
    9595FunctionExecutable* FunctionExecutable::fromGlobalCode(
    9696    const Identifier& name, ExecState& exec, const SourceCode& source,
    97     JSObject*& exception, int overrideLineNumber)
     97    JSObject*& exception, int overrideLineNumber, std::optional<int> functionConstructorParametersEndPosition)
    9898{
    9999    UnlinkedFunctionExecutable* unlinkedExecutable =
    100100        UnlinkedFunctionExecutable::fromGlobalCode(
    101             name, exec, source, exception, overrideLineNumber);
     101            name, exec, source, exception, overrideLineNumber, functionConstructorParametersEndPosition);
    102102    if (!unlinkedExecutable)
    103103        return nullptr;
  • trunk/Source/JavaScriptCore/runtime/FunctionExecutable.h

    r233855 r237054  
    5656    static FunctionExecutable* fromGlobalCode(
    5757        const Identifier& name, ExecState&, const SourceCode&,
    58         JSObject*& exception, int overrideLineNumber);
     58        JSObject*& exception, int overrideLineNumber, std::optional<int> functionConstructorParametersEndPosition);
    5959
    6060    static void destroy(JSCell*);
Note: See TracChangeset for help on using the changeset viewer.