Changeset 273086 in webkit


Ignore:
Timestamp:
Feb 18, 2021 11:14:34 AM (3 years ago)
Author:
msaboff@apple.com
Message:

[JSC] Implement RegExp Match Indices proposal
https://bugs.webkit.org/show_bug.cgi?id=202475

Reviewed by Yusuke Suzuki.

JSTests:

Updated tests.

  • es6/Proxy_internal_get_calls_RegExp.prototype.flags.js:
  • stress/static-getter-in-names.js:
  • test262/config.yaml:

Source/JavaScriptCore:

This implements the latest version of the RegExp match indices proposal (https://github.com/tc39/proposal-regexp-match-indices).
It includes a new 'd' flag to RegExp's to trigger the population of the 'indices' property tree in a Matches result from
RegExp.exec() and related methods. This change is performance neutral on JetStream2.

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGStrengthReductionPhase.cpp:

(JSC::DFG::StrengthReductionPhase::handleNode):

  • runtime/CommonIdentifiers.h:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::fireWatchpointAndMakeAllArrayStructuresSlowPut):
(JSC::JSGlobalObject::visitChildren):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::regExpMatchesArrayWithIndicesStructure const):
(JSC::JSGlobalObject::regExpMatchesIndicesArrayStructure const):

  • runtime/RegExp.cpp:

(JSC::RegExpFunctionalTestCollector::outputOneTest):
(JSC::regexpToSourceString):

  • runtime/RegExp.h:
  • runtime/RegExpMatchesArray.cpp:

(JSC::createEmptyRegExpMatchesArray):
(JSC::createStructureWithIndicesImpl):
(JSC::createIndicesStructureImpl):
(JSC::createRegExpMatchesArrayWithIndicesStructure):
(JSC::createRegExpMatchesIndicesArrayStructure):
(JSC::createRegExpMatchesArrayWithIndicesSlowPutStructure):
(JSC::createRegExpMatchesIndicesArraySlowPutStructure):

  • runtime/RegExpMatchesArray.h:

(JSC::createRegExpMatchesArray):

  • runtime/RegExpPrototype.cpp:

(JSC::RegExpPrototype::finishCreation):
(JSC::flagsString):
(JSC::JSC_DEFINE_HOST_FUNCTION):

  • yarr/YarrFlags.cpp:

(JSC::Yarr::parseFlags):

  • yarr/YarrFlags.h:
  • yarr/YarrInterpreter.h:

(JSC::Yarr::BytecodePattern::hasIndices const):

  • yarr/YarrPattern.h:

(JSC::Yarr::YarrPattern::hasIndices const):

LayoutTests:

Updated tests.

  • js/Object-getOwnPropertyNames-expected.txt:
  • js/regexp-named-capture-groups-expected.txt:
  • js/script-tests/Object-getOwnPropertyNames.js:
  • js/script-tests/regexp-named-capture-groups.js:
Location:
trunk
Files:
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r272933 r273086  
     12021-02-18  Michael Saboff  <msaboff@apple.com>
     2
     3        [JSC] Implement RegExp Match Indices proposal
     4        https://bugs.webkit.org/show_bug.cgi?id=202475
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Updated tests.
     9
     10        * es6/Proxy_internal_get_calls_RegExp.prototype.flags.js:
     11        * stress/static-getter-in-names.js:
     12        * test262/config.yaml:
     13
    1142021-02-16  Yusuke Suzuki  <ysuzuki@apple.com> and Sergey Rubanov <chi187@gmail.com>
    215
  • trunk/JSTests/es6/Proxy_internal_get_calls_RegExp.prototype.flags.js

    r221160 r273086  
    55var p = new Proxy({}, { get: function(o, k) { get.push(k); return o[k]; }});
    66Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags').get.call(p);
    7 return get + '' === "global,ignoreCase,multiline,dotAll,unicode,sticky";
     7return get + '' === "hasIndices,global,ignoreCase,multiline,dotAll,unicode,sticky";
    88     
    99}
  • trunk/JSTests/stress/static-getter-in-names.js

    r221160 r273086  
    44}
    55
    6 shouldBe(JSON.stringify(Object.getOwnPropertyNames(RegExp.prototype).sort()), '["compile","constructor","dotAll","exec","flags","global","ignoreCase","multiline","source","sticky","test","toString","unicode"]');
     6shouldBe(JSON.stringify(Object.getOwnPropertyNames(RegExp.prototype).sort()), '["compile","constructor","dotAll","exec","flags","global","hasIndices","ignoreCase","multiline","source","sticky","test","toString","unicode"]');
    77shouldBe(JSON.stringify(Object.getOwnPropertyNames(/Cocoa/).sort()), '["lastIndex"]');
  • trunk/JSTests/test262/config.yaml

    r272883 r273086  
    2525    - host-gc-required
    2626    # https://bugs.webkit.org/show_bug.cgi?id=202475
    27     - regexp-match-indices
    2827    - top-level-await
    2928  paths:
  • trunk/LayoutTests/ChangeLog

    r273080 r273086  
     12021-02-18  Michael Saboff  <msaboff@apple.com>
     2
     3        [JSC] Implement RegExp Match Indices proposal
     4        https://bugs.webkit.org/show_bug.cgi?id=202475
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Updated tests.
     9
     10        * js/Object-getOwnPropertyNames-expected.txt:
     11        * js/regexp-named-capture-groups-expected.txt:
     12        * js/script-tests/Object-getOwnPropertyNames.js:
     13        * js/script-tests/regexp-named-capture-groups.js:
     14
    1152021-02-18  Kimmo Kinnunen  <kkinnunen@apple.com>
    216
  • trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt

    r270550 r273086  
    5858PASS getSortedOwnPropertyNames(Date.prototype) is ['constructor', 'getDate', 'getDay', 'getFullYear', 'getHours', 'getMilliseconds', 'getMinutes', 'getMonth', 'getSeconds', 'getTime', 'getTimezoneOffset', 'getUTCDate', 'getUTCDay', 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes', 'getUTCMonth', 'getUTCSeconds', 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 'setYear', 'toDateString', 'toGMTString', 'toISOString', 'toJSON', 'toLocaleDateString', 'toLocaleString', 'toLocaleTimeString', 'toString', 'toTimeString', 'toUTCString', 'valueOf']
    5959PASS getSortedOwnPropertyNames(RegExp) is ['$&', "$'", '$*', '$+', '$1', '$2', '$3', '$4', '$5', '$6', '$7', '$8', '$9', '$_', '$`', 'input', 'lastMatch', 'lastParen', 'leftContext', 'length', 'multiline', 'name', 'prototype', 'rightContext']
    60 PASS getSortedOwnPropertyNames(RegExp.prototype) is ['compile', 'constructor', 'dotAll', 'exec', 'flags', 'global', 'ignoreCase', 'multiline', 'source', 'sticky', 'test', 'toString', 'unicode']
     60PASS getSortedOwnPropertyNames(RegExp.prototype) is ['compile', 'constructor', 'dotAll', 'exec', 'flags', 'global', 'hasIndices', 'ignoreCase', 'multiline', 'source', 'sticky', 'test', 'toString', 'unicode']
    6161PASS getSortedOwnPropertyNames(Error) is ['length', 'name', 'prototype', 'stackTraceLimit']
    6262PASS getSortedOwnPropertyNames(Error.prototype) is ['constructor', 'message', 'name', 'toString']
  • trunk/LayoutTests/js/regexp-named-capture-groups-expected.txt

    r259262 r273086  
    1515PASS matchResult1.groups.day is "02"
    1616PASS matchResult1.groups.year is "2001"
    17 PASS Object.getOwnPropertyNames(matchResult1).sort() is ["0","1","2","3","groups","index","input","length"]
     17PASS matchResult1.indices.groups.month is [0,2]
     18PASS matchResult1.indices.groups.day is [3,5]
     19PASS matchResult1.indices.groups.year is [6,10]
     20PASS Object.getOwnPropertyNames(matchResult1).sort() is ["0","1","2","3","groups","index","indices","input","length"]
    1821PASS Object.getOwnPropertyNames(matchResult1.groups).sort() is ["day","month","year"]
     22PASS Object.getOwnPropertyNames(matchResult1.indices.groups).sort() is ["day","month","year"]
    1923PASS matchResult2a[0] is "John W. Smith"
    2024PASS matchResult2a[1] is "John"
    2125PASS matchResult2a[2] is "W."
    2226PASS matchResult2a[3] is "Smith"
     27PASS matchResult2a.indices[1] is [0,4]
     28PASS matchResult2a.indices[2] is [5,7]
     29PASS matchResult2a.indices[3] is [8,13]
    2330PASS matchResult2a[1] is matchResult2a.groups.first_name
    2431PASS matchResult2a[2] is matchResult2a.groups.middle_initial
    2532PASS matchResult2a[3] is matchResult2a.groups.last_name
    26 PASS Object.getOwnPropertyNames(matchResult1).sort() is ["0","1","2","3","groups","index","input","length"]
     33PASS Object.getOwnPropertyNames(matchResult1).sort() is ["0","1","2","3","groups","index","indices","input","length"]
    2734PASS matchResult2b[0] is "Sally Brown"
    2835PASS matchResult2b[1] is "Sally"
    2936PASS matchResult2b[2] is undefined.
    3037PASS matchResult2b[3] is "Brown"
     38PASS matchResult2b.indices[1] is [0,5]
     39PASS matchResult2b.indices[2] is undefined.
     40PASS matchResult2b.indices[3] is [6,11]
    3141PASS matchResult2b[1] is matchResult2b.groups.first_name
    3242PASS matchResult2b[2] is matchResult2b.groups.middle_initial
    3343PASS matchResult2b[3] is matchResult2b.groups.last_name
    34 PASS Object.getOwnPropertyNames(matchResult1).sort() is ["0","1","2","3","groups","index","input","length"]
     44PASS Object.getOwnPropertyNames(matchResult1).sort() is ["0","1","2","3","groups","index","indices","input","length"]
    3545PASS re3.toString() is "\/^(?<part1>.*):(?<part2>.*):\\k<part2>:\\k<part1>$\/"
    3646PASS re3.test("a:b:b:a") is true
  • trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js

    r270550 r273086  
    6767    "Date.prototype": "['constructor', 'getDate', 'getDay', 'getFullYear', 'getHours', 'getMilliseconds', 'getMinutes', 'getMonth', 'getSeconds', 'getTime', 'getTimezoneOffset', 'getUTCDate', 'getUTCDay', 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes', 'getUTCMonth', 'getUTCSeconds', 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 'setYear', 'toDateString', 'toGMTString', 'toISOString', 'toJSON', 'toLocaleDateString', 'toLocaleString', 'toLocaleTimeString', 'toString', 'toTimeString', 'toUTCString', 'valueOf']",
    6868    "RegExp": "['$&', \"$'\", '$*', '$+', '$1', '$2', '$3', '$4', '$5', '$6', '$7', '$8', '$9', '$_', '$`', 'input', 'lastMatch', 'lastParen', 'leftContext', 'length', 'multiline', 'name', 'prototype', 'rightContext']",
    69     "RegExp.prototype": "['compile', 'constructor', 'dotAll', 'exec', 'flags', 'global', 'ignoreCase', 'multiline', 'source', 'sticky', 'test', 'toString', 'unicode']",
     69    "RegExp.prototype": "['compile', 'constructor', 'dotAll', 'exec', 'flags', 'global', 'hasIndices', 'ignoreCase', 'multiline', 'source', 'sticky', 'test', 'toString', 'unicode']",
    7070    "Error": "['length', 'name', 'prototype', 'stackTraceLimit']",
    7171    "Error.prototype": "['constructor', 'message', 'name', 'toString']",
  • trunk/LayoutTests/js/script-tests/regexp-named-capture-groups.js

    r259262 r273086  
    1616shouldBe('Object.getOwnPropertyNames(execResult1.groups).sort()', '["day","month","year"]');
    1717
    18 var matchResult1 = src1.match(re1);
     18var matchResult1 = src1.match(new RegExp(re1, 'd'));
    1919shouldBe('matchResult1[0]', '"01/02/2001"');
    2020shouldBe('matchResult1.groups.month', '"01"');
    2121shouldBe('matchResult1.groups.day', '"02"');
    2222shouldBe('matchResult1.groups.year', '"2001"');
    23 shouldBe('Object.getOwnPropertyNames(matchResult1).sort()', '["0","1","2","3","groups","index","input","length"]');
     23shouldBe('matchResult1.indices.groups.month', '[0,2]');
     24shouldBe('matchResult1.indices.groups.day', '[3,5]');
     25shouldBe('matchResult1.indices.groups.year', '[6,10]');
     26shouldBe('Object.getOwnPropertyNames(matchResult1).sort()', '["0","1","2","3","groups","index","indices","input","length"]');
    2427shouldBe('Object.getOwnPropertyNames(matchResult1.groups).sort()', '["day","month","year"]');
     28shouldBe('Object.getOwnPropertyNames(matchResult1.indices.groups).sort()', '["day","month","year"]');
    2529
    26 var re2 = /(?<first_name>\w+)\s(?:(?<middle_initial>\w\.)\s)?(?<last_name>\w+)/;
     30var re2 = /(?<first_name>\w+)\s(?:(?<middle_initial>\w\.)\s)?(?<last_name>\w+)/d;
    2731var matchResult2a = "John W. Smith".match(re2);
    2832
     
    3135shouldBe('matchResult2a[2]', '"W."');
    3236shouldBe('matchResult2a[3]', '"Smith"');
     37shouldBe('matchResult2a.indices[1]', '[0,4]');
     38shouldBe('matchResult2a.indices[2]', '[5,7]');
     39shouldBe('matchResult2a.indices[3]', '[8,13]');
    3340shouldBe('matchResult2a[1]', 'matchResult2a.groups.first_name');
    3441shouldBe('matchResult2a[2]', 'matchResult2a.groups.middle_initial');
    3542shouldBe('matchResult2a[3]', 'matchResult2a.groups.last_name');
    36 shouldBe('Object.getOwnPropertyNames(matchResult1).sort()', '["0","1","2","3","groups","index","input","length"]');
     43shouldBe('Object.getOwnPropertyNames(matchResult1).sort()', '["0","1","2","3","groups","index","indices","input","length"]');
    3744
    3845// Verify that named groups that aren't matched are undefined.
     
    4350shouldBeUndefined('matchResult2b[2]');
    4451shouldBe('matchResult2b[3]', '"Brown"');
     52shouldBe('matchResult2b.indices[1]', '[0,5]');
     53shouldBeUndefined('matchResult2b.indices[2]');
     54shouldBe('matchResult2b.indices[3]', '[6,11]');
    4555shouldBe('matchResult2b[1]', 'matchResult2b.groups.first_name');
    4656shouldBe('matchResult2b[2]', 'matchResult2b.groups.middle_initial');
    4757shouldBe('matchResult2b[3]', 'matchResult2b.groups.last_name');
    48 shouldBe('Object.getOwnPropertyNames(matchResult1).sort()', '["0","1","2","3","groups","index","input","length"]');
     58shouldBe('Object.getOwnPropertyNames(matchResult1).sort()', '["0","1","2","3","groups","index","indices","input","length"]');
    4959
    5060// Verify that named backreferences work.
  • trunk/Source/JavaScriptCore/ChangeLog

    r273034 r273086  
     12021-02-18  Michael Saboff  <msaboff@apple.com>
     2
     3        [JSC] Implement RegExp Match Indices proposal
     4        https://bugs.webkit.org/show_bug.cgi?id=202475
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        This implements the latest version of the RegExp match indices proposal (https://github.com/tc39/proposal-regexp-match-indices).
     9        It includes a new 'd' flag to RegExp's to trigger the population of the 'indices' property tree in a Matches result from
     10        RegExp.exec() and related methods.  This change is performance neutral on JetStream2.
     11
     12        * dfg/DFGAbstractInterpreterInlines.h:
     13        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     14        * dfg/DFGStrengthReductionPhase.cpp:
     15        (JSC::DFG::StrengthReductionPhase::handleNode):
     16        * runtime/CommonIdentifiers.h:
     17        * runtime/JSGlobalObject.cpp:
     18        (JSC::JSGlobalObject::init):
     19        (JSC::JSGlobalObject::fireWatchpointAndMakeAllArrayStructuresSlowPut):
     20        (JSC::JSGlobalObject::visitChildren):
     21        * runtime/JSGlobalObject.h:
     22        (JSC::JSGlobalObject::regExpMatchesArrayWithIndicesStructure const):
     23        (JSC::JSGlobalObject::regExpMatchesIndicesArrayStructure const):
     24        * runtime/RegExp.cpp:
     25        (JSC::RegExpFunctionalTestCollector::outputOneTest):
     26        (JSC::regexpToSourceString):
     27        * runtime/RegExp.h:
     28        * runtime/RegExpMatchesArray.cpp:
     29        (JSC::createEmptyRegExpMatchesArray):
     30        (JSC::createStructureWithIndicesImpl):
     31        (JSC::createIndicesStructureImpl):
     32        (JSC::createRegExpMatchesArrayWithIndicesStructure):
     33        (JSC::createRegExpMatchesIndicesArrayStructure):
     34        (JSC::createRegExpMatchesArrayWithIndicesSlowPutStructure):
     35        (JSC::createRegExpMatchesIndicesArraySlowPutStructure):
     36        * runtime/RegExpMatchesArray.h:
     37        (JSC::createRegExpMatchesArray):
     38        * runtime/RegExpPrototype.cpp:
     39        (JSC::RegExpPrototype::finishCreation):
     40        (JSC::flagsString):
     41        (JSC::JSC_DEFINE_HOST_FUNCTION):
     42        * yarr/YarrFlags.cpp:
     43        (JSC::Yarr::parseFlags):
     44        * yarr/YarrFlags.h:
     45        * yarr/YarrInterpreter.h:
     46        (JSC::Yarr::BytecodePattern::hasIndices const):
     47        * yarr/YarrPattern.h:
     48        (JSC::Yarr::YarrPattern::hasIndices const):
     49
    1502021-02-17  Yusuke Suzuki  <ysuzuki@apple.com>
    251
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r272580 r273086  
    4949#include "NumberConstructor.h"
    5050#include "PutByIdStatus.h"
     51#include "RegExpObject.h"
    5152#include "SetPrivateBrandStatus.h"
    5253#include "StringObject.h"
     
    26082609                if (!globalObject->isHavingABadTime()) {
    26092610                    m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
     2611
     2612                    RegExp* regExp = nullptr;
     2613                    if (node->op() == RegExpExec) {
     2614                        if (Node* regExpObjectNode = node->child2().node()) {
     2615                            if (RegExpObject* regExpObject = regExpObjectNode->dynamicCastConstant<RegExpObject*>(m_vm))
     2616                                regExp = regExpObject->regExp();
     2617                            else if (regExpObjectNode->op() == NewRegexp)
     2618                                regExp = regExpObjectNode->castOperand<RegExp*>();
     2619                        }
     2620                    } else if (node->op() == RegExpExecNonGlobalOrSticky)
     2621                        regExp = node->castOperand<RegExp*>();
     2622
    26102623                    RegisteredStructureSet structureSet;
    2611                     structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayStructure()));
     2624                    // If regExp is unknown, we need to put both regExp MatchesArray structure variants in our set.
     2625                    if (!regExp || !regExp->hasIndices())
     2626                        structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayStructure()));
     2627                    if (!regExp || regExp->hasIndices())
     2628                        structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayWithIndicesStructure()));
    26122629                    setForNode(node, structureSet);
    26132630                    forNode(node).merge(SpecOther);
  • trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp

    r271987 r273086  
    596596                }
    597597
    598                 if ((m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky) && regExp->hasNamedCaptures()) {
    599                     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=176464
    600                     // Implement strength reduction optimization for named capture groups.
    601                     if (verbose)
    602                         dataLog("Giving up because of named capture groups.\n");
    603                     return false;
     598                if ((m_node->op() == RegExpExec || m_node->op() == RegExpExecNonGlobalOrSticky)) {
     599                    if (regExp->hasNamedCaptures()) {
     600                        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=176464
     601                        // Implement strength reduction optimization for named capture groups.
     602                        if (verbose)
     603                            dataLog("Giving up because of named capture groups.\n");
     604                        return false;
     605                    }
     606
     607                    if (regExp->hasIndices()) {
     608                        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=220930
     609                        // Implement strength reduction optimization for RegExp with match indices.
     610                        if (verbose)
     611                            dataLog("Giving up because of match indices.\n");
     612                        return false;
     613                    }
    604614                }
    605615
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r269531 r273086  
    129129    macro(groups) \
    130130    macro(has) \
     131    macro(hasIndices) \
    131132    macro(hasOwnProperty) \
    132133    macro(hash) \
     
    139140    macro(ignorePunctuation) \
    140141    macro(index) \
     142    macro(indices) \
    141143    macro(inferredName) \
    142144    macro(input) \
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r272885 r273086  
    805805    m_regExpStructure.set(vm, this, RegExpObject::createStructure(vm, this, m_regExpPrototype.get()));
    806806    m_regExpMatchesArrayStructure.set(vm, this, createRegExpMatchesArrayStructure(vm, this));
     807    m_regExpMatchesArrayWithIndicesStructure.set(vm, this, createRegExpMatchesArrayWithIndicesStructure(vm, this));
     808    m_regExpMatchesIndicesArrayStructure.set(vm, this, createRegExpMatchesIndicesArrayStructure(vm, this));
    807809
    808810    m_moduleRecordStructure.initLater(
     
    17491751    slowPutStructure = createRegExpMatchesArraySlowPutStructure(vm, this);
    17501752    m_regExpMatchesArrayStructure.set(vm, this, slowPutStructure);
     1753    slowPutStructure = createRegExpMatchesArrayWithIndicesSlowPutStructure(vm, this);
     1754    m_regExpMatchesArrayWithIndicesStructure.set(vm, this, slowPutStructure);
     1755    slowPutStructure = createRegExpMatchesIndicesArraySlowPutStructure(vm, this);
     1756    m_regExpMatchesIndicesArrayStructure.set(vm, this, slowPutStructure);
    17511757    slowPutStructure = ClonedArguments::createSlowPutStructure(vm, this, m_objectPrototype.get());
    17521758    m_clonedArgumentsStructure.set(vm, this, slowPutStructure);
     
    20262032    thisObject->m_accessorPropertyDescriptorObjectStructure.visit(visitor);
    20272033    visitor.append(thisObject->m_regExpMatchesArrayStructure);
     2034    visitor.append(thisObject->m_regExpMatchesArrayWithIndicesStructure);
     2035    visitor.append(thisObject->m_regExpMatchesIndicesArrayStructure);
    20282036    thisObject->m_moduleRecordStructure.visit(visitor);
    20292037    thisObject->m_moduleNamespaceObjectStructure.visit(visitor);
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r272885 r273086  
    418418    LazyProperty<JSGlobalObject, Structure> m_accessorPropertyDescriptorObjectStructure;
    419419    WriteBarrier<Structure> m_regExpMatchesArrayStructure;
     420    WriteBarrier<Structure> m_regExpMatchesArrayWithIndicesStructure;
     421    WriteBarrier<Structure> m_regExpMatchesIndicesArrayStructure;
    420422    LazyProperty<JSGlobalObject, Structure> m_moduleRecordStructure;
    421423    LazyProperty<JSGlobalObject, Structure> m_moduleNamespaceObjectStructure;
     
    827829    Structure* accessorPropertyDescriptorObjectStructure() const { return m_accessorPropertyDescriptorObjectStructure.get(this); }
    828830    Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
     831    Structure* regExpMatchesArrayWithIndicesStructure() const { return m_regExpMatchesArrayWithIndicesStructure.get(); }
     832    Structure* regExpMatchesIndicesArrayStructure() const { return m_regExpMatchesIndicesArrayStructure.get(); }
    829833    Structure* moduleRecordStructure() const { return m_moduleRecordStructure.get(this); }
    830834    Structure* moduleNamespaceObjectStructure() const { return m_moduleNamespaceObjectStructure.get(this); }
  • trunk/Source/JavaScriptCore/runtime/RegExp.cpp

    r263117 r273086  
    5656        if (regExp->ignoreCase())
    5757            fputc('i', m_file);
     58        if (regExp->hasIndices())
     59            fputc('d', m_file);
    5860        if (regExp->multiline())
    5961            fputc('m', m_file);
     
    489491    if (regExp->ignoreCase())
    490492        postfix[index++] = 'i';
     493    if (regExp->hasIndices())
     494        postfix[index] = 'd';
    491495    if (regExp->multiline())
    492496        postfix[index] = 'm';
  • trunk/Source/JavaScriptCore/runtime/RegExp.h

    r260415 r273086  
    6565    bool unicode() const { return m_flags.contains(Yarr::Flags::Unicode); }
    6666    bool dotAll() const { return m_flags.contains(Yarr::Flags::DotAll); }
     67    bool hasIndices() const { return m_flags.contains(Yarr::Flags::HasIndices); }
    6768
    6869    const String& pattern() const { return m_patternString; }
  • trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp

    r252514 r273086  
    4141
    4242    if (UNLIKELY(globalObject->isHavingABadTime())) {
    43         array = JSArray::tryCreateUninitializedRestricted(scope, &deferralContext, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
     43        array = JSArray::tryCreateUninitializedRestricted(scope, &deferralContext,
     44            regExp->hasIndices() ? globalObject->regExpMatchesArrayWithIndicesStructure() : globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
    4445        // FIXME: we should probably throw an out of memory error here, but
    4546        // when making this change we should check that all clients of this
     
    5556        }
    5657    } else {
    57         array = tryCreateUninitializedRegExpMatchesArray(scope, &deferralContext, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
     58        array = tryCreateUninitializedRegExpMatchesArray(scope, &deferralContext,
     59            regExp->hasIndices() ? globalObject->regExpMatchesArrayWithIndicesStructure() : globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
    5860        RELEASE_ASSERT(array);
    5961       
     
    6971    array->putDirectWithoutBarrier(RegExpMatchesArrayInputPropertyOffset, input);
    7072    array->putDirectWithoutBarrier(RegExpMatchesArrayGroupsPropertyOffset, jsUndefined());
     73    if (regExp->hasIndices())
     74        array->putDirectWithoutBarrier(RegExpMatchesArrayIndicesPropertyOffset, jsUndefined());
    7175    return array;
    7276}
     
    8589}
    8690
     91static Structure* createStructureWithIndicesImpl(VM& vm, JSGlobalObject* globalObject, IndexingType indexingType)
     92{
     93    Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType);
     94    PropertyOffset offset;
     95    structure = Structure::addPropertyTransition(vm, structure, vm.propertyNames->index, 0, offset);
     96    ASSERT(offset == RegExpMatchesArrayIndexPropertyOffset);
     97    structure = Structure::addPropertyTransition(vm, structure, vm.propertyNames->input, 0, offset);
     98    ASSERT(offset == RegExpMatchesArrayInputPropertyOffset);
     99    structure = Structure::addPropertyTransition(vm, structure, vm.propertyNames->groups, 0, offset);
     100    ASSERT(offset == RegExpMatchesArrayGroupsPropertyOffset);
     101    structure = Structure::addPropertyTransition(vm, structure, vm.propertyNames->indices, 0, offset);
     102    ASSERT(offset == RegExpMatchesArrayIndicesPropertyOffset);
     103    return structure;
     104}
     105
     106static Structure* createIndicesStructureImpl(VM& vm, JSGlobalObject* globalObject, IndexingType indexingType)
     107{
     108    Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType);
     109    PropertyOffset offset;
     110    structure = Structure::addPropertyTransition(vm, structure, vm.propertyNames->groups, 0, offset);
     111    ASSERT(offset == RegExpMatchesIndicesGroupsPropertyOffset);
     112    return structure;
     113}
     114
    87115Structure* createRegExpMatchesArrayStructure(VM& vm, JSGlobalObject* globalObject)
    88116{
    89117    return createStructureImpl(vm, globalObject, ArrayWithContiguous);
     118}
     119
     120Structure* createRegExpMatchesArrayWithIndicesStructure(VM& vm, JSGlobalObject* globalObject)
     121{
     122    return createStructureWithIndicesImpl(vm, globalObject, ArrayWithContiguous);
     123}
     124
     125Structure* createRegExpMatchesIndicesArrayStructure(VM& vm, JSGlobalObject* globalObject)
     126{
     127    return createIndicesStructureImpl(vm, globalObject, ArrayWithContiguous);
    90128}
    91129
     
    95133}
    96134
     135Structure* createRegExpMatchesArrayWithIndicesSlowPutStructure(VM& vm, JSGlobalObject* globalObject)
     136{
     137    return createStructureWithIndicesImpl(vm, globalObject, ArrayWithSlowPutArrayStorage);
     138}
     139
     140Structure* createRegExpMatchesIndicesArraySlowPutStructure(VM& vm, JSGlobalObject* globalObject)
     141{
     142    return createIndicesStructureImpl(vm, globalObject, ArrayWithSlowPutArrayStorage);
     143}
     144
    97145} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.h

    r264688 r273086  
    3434static const PropertyOffset RegExpMatchesArrayInputPropertyOffset = 101;
    3535static const PropertyOffset RegExpMatchesArrayGroupsPropertyOffset = 102;
     36static const PropertyOffset RegExpMatchesArrayIndicesPropertyOffset = 103;
     37static const PropertyOffset RegExpMatchesIndicesGroupsPropertyOffset = 100;
    3638
    3739ALWAYS_INLINE JSArray* tryCreateUninitializedRegExpMatchesArray(ObjectInitializationScope& scope, GCDeferralContext* deferralContext, Structure* structure, unsigned initialLength)
     
    7779   
    7880    JSArray* array;
     81    JSArray* indicesArray = nullptr;
    7982
    8083    // FIXME: This should handle array allocation errors gracefully.
     
    8386    unsigned numSubpatterns = regExp->numSubpatterns();
    8487    bool hasNamedCaptures = regExp->hasNamedCaptures();
     88    bool createIndices = regExp->hasIndices();
    8589    JSObject* groups = hasNamedCaptures ? constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure()) : nullptr;
    86     Structure* matchStructure = globalObject->regExpMatchesArrayStructure();
     90    Structure* matchStructure = createIndices ? globalObject->regExpMatchesArrayWithIndicesStructure() : globalObject->regExpMatchesArrayStructure();
     91
     92    JSObject* indicesGroups = createIndices && hasNamedCaptures ? constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure()) : nullptr;
    8793
    8894    auto setProperties = [&] () {
     
    95101        auto size = matchStructure->outOfLineSize();
    96102        gcSafeZeroMemory(static_cast<JSValue*>(array->butterfly()->base(0, capacity)), (capacity - size) * sizeof(JSValue));
     103
     104        if (createIndices) {
     105            array->putDirect(vm, RegExpMatchesArrayIndicesPropertyOffset, indicesArray);
     106
     107            Structure* indicesStructure = globalObject->regExpMatchesIndicesArrayStructure();
     108
     109            indicesArray->putDirect(vm, RegExpMatchesIndicesGroupsPropertyOffset, indicesGroups);
     110
     111            ASSERT(!indicesArray->butterfly()->indexingHeader()->preCapacity(indicesStructure));
     112            auto indicesCapacity = indicesStructure->outOfLineCapacity();
     113            auto indicesSize = indicesStructure->outOfLineSize();
     114            gcSafeZeroMemory(static_cast<JSValue*>(indicesArray->butterfly()->base(0, indicesCapacity)), (indicesCapacity - indicesSize) * sizeof(JSValue));
     115        }
     116    };
     117
     118    auto createIndexArray = [&] (GCDeferralContext& deferralContext, int start, int end) {
     119        ObjectInitializationScope scope(vm);
     120
     121        JSArray* result = JSArray::tryCreateUninitializedRestricted(scope, &deferralContext, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 2);
     122        result->initializeIndexWithoutBarrier(scope, 0, jsNumber(start));
     123        result->initializeIndexWithoutBarrier(scope, 1, jsNumber(end));
     124       
     125        return result;
    97126    };
    98127
    99128    if (UNLIKELY(globalObject->isHavingABadTime())) {
    100129        GCDeferralContext deferralContext(vm.heap);
    101         ObjectInitializationScope scope(vm);
    102         array = JSArray::tryCreateUninitializedRestricted(scope, &deferralContext, matchStructure, numSubpatterns + 1);
     130        ObjectInitializationScope matchesArrayScope(vm);
     131        ObjectInitializationScope indicesArrayScope(vm);
     132        array = JSArray::tryCreateUninitializedRestricted(matchesArrayScope, &deferralContext, matchStructure, numSubpatterns + 1);
     133
     134        if (createIndices)
     135            indicesArray = JSArray::tryCreateUninitializedRestricted(indicesArrayScope, &deferralContext, globalObject->regExpMatchesIndicesArrayStructure(), numSubpatterns + 1);
    103136
    104137        // FIXME: we should probably throw an out of memory error here, but
     
    110143        setProperties();
    111144       
    112         array->initializeIndexWithoutBarrier(scope, 0, jsSubstringOfResolved(vm, &deferralContext, input, result.start, result.end - result.start));
    113        
     145        array->initializeIndexWithoutBarrier(matchesArrayScope, 0, jsSubstringOfResolved(vm, &deferralContext, input, result.start, result.end - result.start));
     146
    114147        for (unsigned i = 1; i <= numSubpatterns; ++i) {
    115148            int start = subpatternResults[2 * i];
     
    119152            else
    120153                value = jsUndefined();
    121             array->initializeIndexWithoutBarrier(scope, i, value);
     154            array->initializeIndexWithoutBarrier(matchesArrayScope, i, value);
     155        }
     156
     157        if (createIndices) {
     158            for (unsigned i = 0; i <= numSubpatterns; ++i) {
     159                int start = subpatternResults[2 * i];
     160                JSValue value;
     161                if (start >= 0)
     162                    indicesArray->initializeIndexWithoutBarrier(indicesArrayScope, i, createIndexArray(deferralContext, start, subpatternResults[2 * i + 1]));
     163                else
     164                    indicesArray->initializeIndexWithoutBarrier(indicesArrayScope, i, jsUndefined());
     165            }
    122166        }
    123167    } else {
    124168        GCDeferralContext deferralContext(vm.heap);
    125         ObjectInitializationScope scope(vm);
    126         array = tryCreateUninitializedRegExpMatchesArray(scope, &deferralContext, matchStructure, numSubpatterns + 1);
     169        ObjectInitializationScope matchesArrayScope(vm);
     170        ObjectInitializationScope indicesArrayScope(vm);
     171        array = tryCreateUninitializedRegExpMatchesArray(matchesArrayScope, &deferralContext, matchStructure, numSubpatterns + 1);
     172
     173        if (createIndices)
     174            indicesArray = tryCreateUninitializedRegExpMatchesArray(indicesArrayScope, &deferralContext, globalObject->regExpMatchesIndicesArrayStructure(), numSubpatterns + 1);
    127175
    128176        // FIXME: we should probably throw an out of memory error here, but
     
    134182        setProperties();
    135183       
    136         array->initializeIndexWithoutBarrier(scope, 0, jsSubstringOfResolved(vm, &deferralContext, input, result.start, result.end - result.start), ArrayWithContiguous);
     184        array->initializeIndexWithoutBarrier(matchesArrayScope, 0, jsSubstringOfResolved(vm, &deferralContext, input, result.start, result.end - result.start), ArrayWithContiguous);
    137185       
    138186        for (unsigned i = 1; i <= numSubpatterns; ++i) {
     
    143191            else
    144192                value = jsUndefined();
    145             array->initializeIndexWithoutBarrier(scope, i, value, ArrayWithContiguous);
     193            array->initializeIndexWithoutBarrier(matchesArrayScope, i, value, ArrayWithContiguous);
     194        }
     195
     196        if (createIndices) {
     197            for (unsigned i = 0; i <= numSubpatterns; ++i) {
     198                int start = subpatternResults[2 * i];
     199                JSValue value;
     200                if (start >= 0)
     201                    indicesArray->initializeIndexWithoutBarrier(indicesArrayScope, i, createIndexArray(deferralContext, start, subpatternResults[2 * i + 1]));
     202                else
     203                    indicesArray->initializeIndexWithoutBarrier(indicesArrayScope, i, jsUndefined());
     204            }
    146205        }
    147206    }
     
    149208    // Now the object is safe to scan by GC.
    150209
    151     // We initialize the groups object late as it could allocate, which with the current API could cause
     210    // We initialize the groups and indices objects late as they could allocate, which with the current API could cause
    152211    // allocations.
    153212    if (hasNamedCaptures) {
    154213        for (unsigned i = 1; i <= numSubpatterns; ++i) {
    155214            String groupName = regExp->getCaptureGroupName(i);
    156             if (!groupName.isEmpty())
     215            if (!groupName.isEmpty()) {
    157216                groups->putDirect(vm, Identifier::fromString(vm, groupName), array->getIndexQuickly(i));
     217                if (createIndices)
     218                    indicesGroups->putDirect(vm, Identifier::fromString(vm, groupName), indicesArray->getIndexQuickly(i));
     219            }
    158220        }
    159221    }
     222
    160223    return array;
    161224}
     
    174237JSArray* createEmptyRegExpMatchesArray(JSGlobalObject*, JSString*, RegExp*);
    175238Structure* createRegExpMatchesArrayStructure(VM&, JSGlobalObject*);
     239Structure* createRegExpMatchesArrayWithIndicesStructure(VM&, JSGlobalObject*);
     240Structure* createRegExpMatchesIndicesArrayStructure(VM&, JSGlobalObject*);
    176241Structure* createRegExpMatchesArraySlowPutStructure(VM&, JSGlobalObject*);
     242Structure* createRegExpMatchesArrayWithIndicesSlowPutStructure(VM&, JSGlobalObject*);
     243Structure* createRegExpMatchesIndicesArraySlowPutStructure(VM&, JSGlobalObject*);
    177244
    178245} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/RegExpPrototype.cpp

    r267594 r273086  
    4141static JSC_DECLARE_HOST_FUNCTION(regExpProtoFuncToString);
    4242static JSC_DECLARE_HOST_FUNCTION(regExpProtoGetterGlobal);
     43static JSC_DECLARE_HOST_FUNCTION(regExpProtoGetterHasIndices);
    4344static JSC_DECLARE_HOST_FUNCTION(regExpProtoGetterIgnoreCase);
    4445static JSC_DECLARE_HOST_FUNCTION(regExpProtoGetterMultiline);
     
    6566    JSC_NATIVE_GETTER_WITHOUT_TRANSITION(vm.propertyNames->global, regExpProtoGetterGlobal, PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
    6667    JSC_NATIVE_GETTER_WITHOUT_TRANSITION(vm.propertyNames->dotAll, regExpProtoGetterDotAll, PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
     68    JSC_NATIVE_GETTER_WITHOUT_TRANSITION(vm.propertyNames->hasIndices, regExpProtoGetterHasIndices, PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
    6769    JSC_NATIVE_GETTER_WITHOUT_TRANSITION(vm.propertyNames->ignoreCase, regExpProtoGetterIgnoreCase, PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
    6870    JSC_NATIVE_GETTER_WITHOUT_TRANSITION(vm.propertyNames->multiline, regExpProtoGetterMultiline, PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
     
    171173    auto scope = DECLARE_THROW_SCOPE(vm);
    172174
     175    JSValue indicesValue = regexp->get(globalObject, vm.propertyNames->hasIndices);
     176    RETURN_IF_EXCEPTION(scope, string);
    173177    JSValue globalValue = regexp->get(globalObject, vm.propertyNames->global);
    174178    RETURN_IF_EXCEPTION(scope, string);
     
    185189
    186190    unsigned index = 0;
     191    if (indicesValue.toBoolean(globalObject))
     192        string[index++] = 'd';
    187193    if (globalValue.toBoolean(globalObject))
    188194        string[index++] = 'g';
     
    246252
    247253    return JSValue::encode(jsBoolean(regexp->regExp()->global()));
     254}
     255
     256JSC_DEFINE_HOST_FUNCTION(regExpProtoGetterHasIndices, (JSGlobalObject* globalObject, CallFrame* callFrame))
     257{
     258    VM& vm = globalObject->vm();
     259    auto scope = DECLARE_THROW_SCOPE(vm);
     260
     261    JSValue thisValue = callFrame->thisValue();
     262    auto* regexp = jsDynamicCast<RegExpObject*>(vm, thisValue);
     263    if (UNLIKELY(!regexp)) {
     264        if (thisValue == globalObject->regExpPrototype())
     265            return JSValue::encode(jsUndefined());
     266        return throwVMTypeError(globalObject, scope, "The RegExp.prototype.hasIndices getter can only be called on a RegExp object"_s);
     267    }
     268
     269    return JSValue::encode(jsBoolean(regexp->regExp()->hasIndices()));
    248270}
    249271
  • trunk/Source/JavaScriptCore/yarr/YarrFlags.cpp

    r242776 r273086  
    3838    for (auto character : string.codeUnits()) {
    3939        switch (character) {
     40        case 'd':
     41            if (flags.contains(Flags::HasIndices))
     42                return WTF::nullopt;
     43            flags.add(Flags::HasIndices);
     44            break;
     45
    4046        case 'g':
    4147            if (flags.contains(Flags::Global))
  • trunk/Source/JavaScriptCore/yarr/YarrFlags.h

    r242776 r273086  
    3737    Unicode = 1 << 4,
    3838    DotAll = 1 << 5,
    39     DeletedValue = 1 << 6
     39    HasIndices = 1 << 6,
     40    DeletedValue = 1 << 7
    4041};
    4142
  • trunk/Source/JavaScriptCore/yarr/YarrInterpreter.h

    r246408 r273086  
    372372    bool ignoreCase() const { return m_flags.contains(Flags::IgnoreCase); }
    373373    bool multiline() const { return m_flags.contains(Flags::Multiline); }
     374    bool hasIndices() const { return m_flags.contains(Flags::HasIndices); }
    374375    bool sticky() const { return m_flags.contains(Flags::Sticky); }
    375376    bool unicode() const { return m_flags.contains(Flags::Unicode); }
  • trunk/Source/JavaScriptCore/yarr/YarrPattern.h

    r261464 r273086  
    525525    bool ignoreCase() const { return m_flags.contains(Flags::IgnoreCase); }
    526526    bool multiline() const { return m_flags.contains(Flags::Multiline); }
     527    bool hasIndices() const { return m_flags.contains(Flags::HasIndices); }
    527528    bool sticky() const { return m_flags.contains(Flags::Sticky); }
    528529    bool unicode() const { return m_flags.contains(Flags::Unicode); }
Note: See TracChangeset for help on using the changeset viewer.