diff --git a/src/builtins/BuiltinRegExp.cpp b/src/builtins/BuiltinRegExp.cpp index f0330165d0..ab0501e46d 100644 --- a/src/builtins/BuiltinRegExp.cpp +++ b/src/builtins/BuiltinRegExp.cpp @@ -610,6 +610,11 @@ static Value builtinRegExpDotAllGetter(ExecutionState& state, Value thisValue, s return builtinRegExpOptionGetterHelper(state, thisValue, RegExpObject::Option::DotAll); } +static Value builtinRegExpHasIndicesGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) +{ + return builtinRegExpOptionGetterHelper(state, thisValue, RegExpObject::Option::HasIndices); +} + static Value builtinRegExpIgnoreCaseGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) { return builtinRegExpOptionGetterHelper(state, thisValue, RegExpObject::Option::IgnoreCase); @@ -854,6 +859,13 @@ void GlobalObject::installRegExp(ExecutionState& state) m_regexpPrototype->directDefineOwnProperty(state, ObjectPropertyName(state, strings->dotAll), desc); } + { + Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getHasIndices, builtinRegExpHasIndicesGetter, 0, NativeFunctionInfo::Strict)); + JSGetterSetter gs(getter, Value()); + ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent); + m_regexpPrototype->directDefineOwnProperty(state, ObjectPropertyName(state, strings->hasIndices), desc); + } + { Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getIgnoreCase, builtinRegExpIgnoreCaseGetter, 0, NativeFunctionInfo::Strict)); JSGetterSetter gs(getter, Value()); diff --git a/src/runtime/RegExpObject.cpp b/src/runtime/RegExpObject.cpp index ec4e1564be..6701952b17 100644 --- a/src/runtime/RegExpObject.cpp +++ b/src/runtime/RegExpObject.cpp @@ -181,6 +181,7 @@ bool RegExpObject::defineOwnProperty(ExecutionState& state, const ObjectProperty || name->equals(state.context()->staticStrings().unicode.string()) || name->equals(state.context()->staticStrings().sticky.string()) || name->equals(state.context()->staticStrings().dotAll.string()) + || name->equals(state.context()->staticStrings().hasIndices.string()) || name->equals(state.context()->staticStrings().source.string()) || name->equals(state.context()->staticStrings().flags.string())) { m_hasOwnPropertyWhichHasDefinedFromRegExpPrototype = true; @@ -203,6 +204,11 @@ RegExpObject::Option RegExpObject::parseOption(ExecutionState& state, String* op auto bufferAccessData = optionString->bufferAccessData(); for (size_t i = 0; i < bufferAccessData.length; i++) { switch (bufferAccessData.charAt(i)) { + case 'd': + if (tempOption & Option::HasIndices) + ErrorObject::throwBuiltinError(state, ErrorObject::SyntaxError, "RegExp has multiple 'd' flags"); + tempOption = (Option)(tempOption | Option::HasIndices); + break; case 'g': if (tempOption & Option::Global) ErrorObject::throwBuiltinError(state, ErrorObject::SyntaxError, "RegExp has multiple 'g' flags"); @@ -263,7 +269,7 @@ RegExpObject::RegExpCacheEntry& RegExpObject::getCacheEntryAndCompileIfNeeded(Ex JSC::Yarr::YarrPattern* yarrPattern = nullptr; try { JSC::Yarr::ErrorCode errorCode = JSC::Yarr::ErrorCode::NoError; - yarrPattern = JSC::Yarr::YarrPattern::createYarrPattern(source, (JSC::Yarr::RegExpFlags)option, errorCode); + yarrPattern = JSC::Yarr::YarrPattern::createYarrPattern(source, static_cast(static_cast(option) & ~Option::HasIndices), errorCode); yarrError = JSC::Yarr::errorMessage(errorCode); } catch (const std::bad_alloc& e) { ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "got too complicated RegExp pattern to process"); @@ -478,6 +484,41 @@ ArrayObject* RegExpObject::createRegExpMatchedArray(ExecutionState& state, const arr->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().groups), ObjectPropertyDescriptor(Value(groups), ObjectPropertyDescriptor::AllPresent)); } + if (option() & HasIndices) { + ArrayObject* indices = new ArrayObject(state, len); + arr->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().indices), ObjectPropertyDescriptor(Value(indices), ObjectPropertyDescriptor::AllPresent)); + + size_t idx = 0; + for (unsigned i = 0; i < result.m_matchResults.size(); i++) { + for (unsigned j = 0; j < result.m_matchResults[i].size(); j++) { + if (result.m_matchResults[i][j].m_start == std::numeric_limits::max()) { + indices->defineOwnIndexedPropertyWithoutExpanding(state, idx++, Value()); + } else { + ArrayObject* pair = new ArrayObject(state, 2); + pair->defineOwnIndexedPropertyWithoutExpanding(state, 0, Value(result.m_matchResults[i][j].m_start)); + pair->defineOwnIndexedPropertyWithoutExpanding(state, 1, Value(result.m_matchResults[i][j].m_end)); + + indices->defineOwnIndexedPropertyWithoutExpanding(state, idx++, Value(pair)); + } + } + } + + if (m_yarrPattern->m_namedGroupToParenIndex.empty()) { + indices->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().groups), ObjectPropertyDescriptor(Value(), ObjectPropertyDescriptor::AllPresent)); + } else { + Object* groups = new Object(state); + groups->setPrototype(state, Value(Value::Null)); + for (auto it = m_yarrPattern->m_captureGroupNames.begin(); it != m_yarrPattern->m_captureGroupNames.end(); ++it) { + auto foundMapElement = m_yarrPattern->m_namedGroupToParenIndex.find(*it); + if (foundMapElement != m_yarrPattern->m_namedGroupToParenIndex.end()) { + groups->directDefineOwnProperty(state, ObjectPropertyName(state, it->impl()), + ObjectPropertyDescriptor(indices->getOwnProperty(state, ObjectPropertyName(state, foundMapElement->second)).value(state, this), ObjectPropertyDescriptor::AllPresent)); + } + } + indices->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().groups), ObjectPropertyDescriptor(Value(groups), ObjectPropertyDescriptor::AllPresent)); + } + } + // FIXME RegExp should have own Realm internal slot when allocated if (state.context() == this->getFunctionRealm(state)) { if (!this->legacyFeaturesEnabled()) { @@ -534,7 +575,7 @@ Value RegExpObject::regexpFlagsValue(ExecutionState& state, Object* obj) String* RegExpObject::computeRegExpOptionString(ExecutionState& state, Object* obj) { - char flags[7] = { 0 }; + char flags[8] = { 0 }; size_t flagsIdx = 0; size_t cacheIndex = 0; @@ -545,29 +586,34 @@ String* RegExpObject::computeRegExpOptionString(ExecutionState& state, Object* o cacheIndex |= 1 << 0; } + if (opt & RegExpObject::Option::HasIndices) { + flags[flagsIdx++] = 'd'; + cacheIndex |= 1 << 1; + } + if (opt & RegExpObject::Option::IgnoreCase) { flags[flagsIdx++] = 'i'; - cacheIndex |= 1 << 1; + cacheIndex |= 1 << 2; } if (opt & RegExpObject::Option::MultiLine) { flags[flagsIdx++] = 'm'; - cacheIndex |= 1 << 2; + cacheIndex |= 1 << 3; } if (opt & RegExpObject::Option::DotAll) { flags[flagsIdx++] = 's'; - cacheIndex |= 1 << 3; + cacheIndex |= 1 << 4; } if (opt & RegExpObject::Option::Unicode) { flags[flagsIdx++] = 'u'; - cacheIndex |= 1 << 4; + cacheIndex |= 1 << 5; } if (opt & RegExpObject::Option::Sticky) { flags[flagsIdx++] = 'y'; - cacheIndex |= 1 << 5; + cacheIndex |= 1 << 6; } } else { if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().global)).value(state, obj).toBoolean(state)) { @@ -575,29 +621,34 @@ String* RegExpObject::computeRegExpOptionString(ExecutionState& state, Object* o cacheIndex |= 1 << 0; } + if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().hasIndices)).value(state, obj).toBoolean(state)) { + flags[flagsIdx++] = 'd'; + cacheIndex |= 1 << 1; + } + if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().ignoreCase)).value(state, obj).toBoolean(state)) { flags[flagsIdx++] = 'i'; - cacheIndex |= 1 << 1; + cacheIndex |= 1 << 2; } if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().multiline)).value(state, obj).toBoolean(state)) { flags[flagsIdx++] = 'm'; - cacheIndex |= 1 << 2; + cacheIndex |= 1 << 3; } if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().dotAll)).value(state, obj).toBoolean(state)) { flags[flagsIdx++] = 's'; - cacheIndex |= 1 << 3; + cacheIndex |= 1 << 4; } if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().unicode)).value(state, obj).toBoolean(state)) { flags[flagsIdx++] = 'u'; - cacheIndex |= 1 << 4; + cacheIndex |= 1 << 5; } if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().sticky)).value(state, obj).toBoolean(state)) { flags[flagsIdx++] = 'y'; - cacheIndex |= 1 << 5; + cacheIndex |= 1 << 6; } } diff --git a/src/runtime/RegExpObject.h b/src/runtime/RegExpObject.h index 156514c51c..14b5dab1aa 100644 --- a/src/runtime/RegExpObject.h +++ b/src/runtime/RegExpObject.h @@ -56,6 +56,8 @@ class RegExpObject : public DerivedObject { Sticky = 1 << 3, Unicode = 1 << 4, DotAll = 1 << 5, + // HasIndices is not a Yarr property + HasIndices = 1 << 6, }; struct RegExpCacheKey { diff --git a/src/runtime/StaticStrings.cpp b/src/runtime/StaticStrings.cpp index 61d195bb62..e82666ec0e 100644 --- a/src/runtime/StaticStrings.cpp +++ b/src/runtime/StaticStrings.cpp @@ -97,6 +97,7 @@ void StaticStrings::initStaticStrings() INIT_STATIC_STRING(getFlags, "get flags"); INIT_STATIC_STRING(getFormat, "get format"); INIT_STATIC_STRING(getGlobal, "get global"); + INIT_STATIC_STRING(getHasIndices, "get hasIndices"); INIT_STATIC_STRING(getHourCycle, "get hourCycle"); INIT_STATIC_STRING(getHourCycles, "get hourCycles"); INIT_STATIC_STRING(getIgnoreCase, "get ignoreCase"); diff --git a/src/runtime/StaticStrings.h b/src/runtime/StaticStrings.h index 707ccf61c4..0b6a4922a8 100644 --- a/src/runtime/StaticStrings.h +++ b/src/runtime/StaticStrings.h @@ -276,6 +276,7 @@ namespace Escargot { F(grow) \ F(growable) \ F(has) \ + F(hasIndices) \ F(hasInstance) \ F(hasOwn) \ F(hasOwnProperty) \ @@ -287,6 +288,7 @@ namespace Escargot { F(includes) \ F(index) \ F(indexOf) \ + F(indices) \ F(input) \ F(instanceof) \ F(interface) \ @@ -976,6 +978,7 @@ class StaticStrings { AtomicString getFlags; AtomicString getFormat; AtomicString getGlobal; + AtomicString getHasIndices; AtomicString getHourCycle; AtomicString getHourCycles; AtomicString getIgnoreCase; diff --git a/src/runtime/VMInstance.cpp b/src/runtime/VMInstance.cpp index 5abc668984..367733a8ca 100644 --- a/src/runtime/VMInstance.cpp +++ b/src/runtime/VMInstance.cpp @@ -386,8 +386,8 @@ VMInstance::VMInstance(const char* locale, const char* timezone, const char* bas m_staticStrings.initStaticStrings(); m_regexpCache = new (GC) RegExpCacheMap(); - m_regexpOptionStringCache = (ASCIIString**)GC_MALLOC(64 * sizeof(ASCIIString*)); - memset(m_regexpOptionStringCache, 0, 64 * sizeof(ASCIIString*)); + m_regexpOptionStringCache = (ASCIIString**)GC_MALLOC(128 * sizeof(ASCIIString*)); + memset(m_regexpOptionStringCache, 0, 128 * sizeof(ASCIIString*)); #if defined(ENABLE_ICU) #if !defined(OS_WINDOWS_UWP) diff --git a/tools/test/test262/excludelist.orig.xml b/tools/test/test262/excludelist.orig.xml index 71b1a91d28..da18eb37f9 100644 --- a/tools/test/test262/excludelist.orig.xml +++ b/tools/test/test262/excludelist.orig.xml @@ -175,7 +175,6 @@ TODO TODO TODO - TODO TODO TODO TODO @@ -193,19 +192,6 @@ TODO TODO TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO TODO TODO TODO @@ -461,19 +447,6 @@ TODO TODO TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO - TODO TODO TODO TODO