⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 237254 in webkit


Ignore:
Timestamp:
Oct 18, 2018, 6:04:22 AM (8 years ago)
Author:
yusukesuzuki@slowstart.org
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):

  • 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

    r237128 r237254  
    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

    r237253 r237254  
     12018-10-18  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
     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-18  Commit Queue  <commit-queue@webkit.org>
    227
  • trunk/JSTests/test262/expectations.yaml

    r237128 r237254  
    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

    r237245 r237254  
     12018-10-18  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
     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-17  Wenson Hsieh  <wenson_hsieh@apple.com>
    215
  • trunk/LayoutTests/fast/dom/attribute-event-listener-errors-expected.txt

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237245 r237254  
     12018-10-18  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
     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-17  Wenson Hsieh  <wenson_hsieh@apple.com>
    214
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/webappapis/scripting/events/inline-event-handler-ordering-expected.txt

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237253 r237254  
     12018-10-18  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
     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        * parser/Parser.h:
     50        (JSC::Parser<LexerType>::parse):
     51        (JSC::parse):
     52        (JSC::parseFunctionForFunctionConstructor):
     53        * parser/ParserModes.h:
     54        * parser/ParserTokens.h:
     55        (JSC::JSTextPosition::JSTextPosition):
     56        (JSC::JSTokenLocation::JSTokenLocation): Deleted.
     57        * parser/SourceCodeKey.h:
     58        (JSC::SourceCodeKey::SourceCodeKey):
     59        (JSC::SourceCodeKey::operator== const):
     60        * runtime/CodeCache.cpp:
     61        (JSC::CodeCache::getUnlinkedGlobalCodeBlock):
     62        (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable):
     63        * runtime/CodeCache.h:
     64        * runtime/FunctionConstructor.cpp:
     65        (JSC::constructFunctionSkippingEvalEnabledCheck):
     66        * runtime/FunctionExecutable.cpp:
     67        (JSC::FunctionExecutable::fromGlobalCode):
     68        * runtime/FunctionExecutable.h:
     69
    1702018-10-18  Commit Queue  <commit-queue@webkit.org>
    271
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    195195
    196196template <typename LexerType>
    197 String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode)
     197String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, std::optional<int> functionConstructorParametersEndPosition)
    198198{
    199199    String parseError = String();
    … …  
    239239        else if (isAsyncGeneratorWrapperParseMode(parseMode))
    240240            sourceElements = parseAsyncGeneratorFunctionSourceElements(context, parseMode, isArrowFunctionBodyExpression, CheckForStrictMode);
     241        else if (parsingContext == ParsingContext::FunctionConstructor)
     242            sourceElements = parseSingleFunction(context, functionConstructorParametersEndPosition);
    241243        else
    242244            sourceElements = parseSourceElements(context, CheckForStrictMode);
    … …  
    611613    return sourceElements;
    612614}
     615
     616template <typename LexerType>
     617template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseSingleFunction(TreeBuilder& context, std::optional<int> functionConstructorParametersEndPosition)
     618{
     619    TreeSourceElements sourceElements = context.createSourceElements();
     620    TreeStatement statement = 0;
     621    switch (m_token.m_type) {
     622    case FUNCTION:
     623        statement = parseFunctionDeclaration(context, ExportType::NotExported, DeclarationDefaultContext::Standard, functionConstructorParametersEndPosition);
     624        break;
     625    case IDENT:
     626        if (*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped) {
     627            next();
     628            failIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Cannot parse the async function");
     629            statement = parseAsyncFunctionDeclaration(context, ExportType::NotExported, DeclarationDefaultContext::Standard, functionConstructorParametersEndPosition);
     630            break;
     631        }
     632        FALLTHROUGH;
     633    default:
     634        failDueToUnexpectedToken();
     635        break;
     636    }
     637
     638    if (statement) {
     639        context.setEndOffset(statement, m_lastTokenEndPosition.offset);
     640        context.appendStatement(sourceElements, statement);
     641    }
     642
     643    propagateError();
     644    return sourceElements;
     645}
     646
    613647   
    614648template <typename LexerType>
    … …  
    22642298
    22652299template <typename LexerType>
    2266 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)
     2300template <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)
    22672301{
    22682302    RELEASE_ASSERT(isFunctionParseMode(mode));
    … …  
    24602494       
    24612495        matchOrFail(OPENBRACE, "Expected an opening '{' at the start of a ", stringForFunctionMode(mode), " body");
     2496
     2497        // If the code is invoked from function constructor, we need to ensure that parameters are only composed by the string offered as parameters.
     2498        if (functionConstructorParametersEndPosition)
     2499            semanticFailIfFalse(lastTokenEndPosition().offset == *functionConstructorParametersEndPosition, "Parameters should match arguments offered as parameters in Function constructor");
    24622500       
    24632501        // BytecodeGenerator emits code to throw TypeError when a class constructor is "call"ed.
    … …  
    25942632
    25952633template <typename LexerType>
    2596 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext)
     2634template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext, std::optional<int> functionConstructorParametersEndPosition)
    25972635{
    25982636    ASSERT(match(FUNCTION));
    … …  
    26312669    }
    26322670
    2633     failIfFalse((parseFunctionInfo(context, requirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this function");
     2671    failIfFalse((parseFunctionInfo(context, requirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration, functionConstructorParametersEndPosition)), "Cannot parse this function");
    26342672    ASSERT(functionInfo.name);
    26352673
    … …  
    26522690
    26532691template <typename LexerType>
    2654 template <class TreeBuilder> TreeStatement Parser<LexerType>::parseAsyncFunctionDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext)
     2692template <class TreeBuilder> TreeStatement Parser<LexerType>::parseAsyncFunctionDeclaration(TreeBuilder& context, ExportType exportType, DeclarationDefaultContext declarationDefaultContext, std::optional<int> functionConstructorParametersEndPosition)
    26552693{
    26562694    ASSERT(match(FUNCTION));
    … …  
    26892727    }
    26902728
    2691     failIfFalse((parseFunctionInfo(context, requirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration)), "Cannot parse this async function");
     2729    failIfFalse((parseFunctionInfo(context, requirements, parseMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, functionInfo, FunctionDefinitionType::Declaration, functionConstructorParametersEndPosition)), "Cannot parse this async function");
    26922730    failIfFalse(functionInfo.name, "Async function statements must have a name");
    26932731
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r237128 r237254  
    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();
    … …  
    18481848template <typename LexerType>
    18491849template <class ParsedNode>
    1850 std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode)
     1850std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, std::optional<int> functionConstructorParametersEndPosition)
    18511851{
    18521852    int errLine;
    … …  
    18651865    unsigned startColumn = m_source->startColumn().zeroBasedInt();
    18661866
    1867     String parseError = parseInner(calleeName, parseMode);
     1867    String parseError = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition);
    18681868
    18691869    int lineNumber = m_lexer->lineNumber();
    … …  
    19601960    if (source.provider()->source().is8Bit()) {
    19611961        Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData);
    1962         result = parser.parse<ParsedNode>(error, name, parseMode);
     1962        result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program);
    19631963        if (positionBeforeLastNewline)
    19641964            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
    … …  
    19731973        ASSERT_WITH_MESSAGE(defaultConstructorKind == ConstructorKind::None, "BuiltinExecutables::createDefaultConstructor should always use a 8-bit string");
    19741974        Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData);
    1975         result = parser.parse<ParsedNode>(error, name, parseMode);
     1975        result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program);
    19761976        if (positionBeforeLastNewline)
    19771977            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
    … …  
    19871987}
    19881988
     1989inline std::unique_ptr<ProgramNode> parseFunctionForFunctionConstructor(VM& vm, const SourceCode& source, ParserError& error, JSTextPosition* positionBeforeLastNewline, std::optional<int> functionConstructorParametersEndPosition)
     1990{
     1991    ASSERT(!source.provider()->source().isNull());
     1992
     1993    MonotonicTime before;
     1994    if (UNLIKELY(Options::reportParseTimes()))
     1995        before = MonotonicTime::now();
     1996
     1997    Identifier name;
     1998    bool isEvalNode = false;
     1999    std::unique_ptr<ProgramNode> result;
     2000    if (source.provider()->source().is8Bit()) {
     2001        Parser<Lexer<LChar>> parser(&vm, source, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, nullptr);
     2002        result = parser.parse<ProgramNode>(error, name, SourceParseMode::ProgramMode, ParsingContext::FunctionConstructor, functionConstructorParametersEndPosition);
     2003        if (positionBeforeLastNewline)
     2004            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
     2005    } else {
     2006        Parser<Lexer<UChar>> parser(&vm, source, JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, ConstructorKind::None, DerivedContextType::None, isEvalNode, EvalContextType::None, nullptr);
     2007        result = parser.parse<ProgramNode>(error, name, SourceParseMode::ProgramMode, ParsingContext::FunctionConstructor, functionConstructorParametersEndPosition);
     2008        if (positionBeforeLastNewline)
     2009            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
     2010    }
     2011
     2012    if (UNLIKELY(Options::reportParseTimes())) {
     2013        MonotonicTime after = MonotonicTime::now();
     2014        ParseHash hash(source);
     2015        dataLogLn(result ? "Parsed #" : "Failed to parse #", hash.hashForCall(), "/#", hash.hashForConstruct(), " in ", (after - before).milliseconds(), " ms.");
     2016    }
     2017
     2018    return result;
     2019}
     2020
     2021
    19892022} // namespace
  • trunk/Source/JavaScriptCore/parser/ParserModes.h

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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

    r237128 r237254  
    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.