diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 33c2854dae..46a2862909 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -164,10 +164,11 @@ CreateRegExpSearchResult(JSContext* cx, const MatchPairs& matches) * steps 3, 9-14, except 12.a.i, 12.c.i.1. */ static RegExpRunStatus -ExecuteRegExpImpl(JSContext* cx, RegExpStatics* res, RegExpShared& re, HandleLinearString input, - size_t searchIndex, MatchPairs* matches, size_t* endIndex) +ExecuteRegExpImpl(JSContext* cx, RegExpStatics* res, MutableHandleRegExpShared re, + HandleLinearString input, size_t searchIndex, MatchPairs* matches, + size_t* endIndex) { - RegExpRunStatus status = re.execute(cx, input, searchIndex, matches, endIndex); + RegExpRunStatus status = RegExpShared::execute(cx, re, input, searchIndex, matches, endIndex); /* Out of spec: Update RegExpStatics. */ if (status == RegExpRunStatus_Success && res) { @@ -175,7 +176,7 @@ ExecuteRegExpImpl(JSContext* cx, RegExpStatics* res, RegExpShared& re, HandleLin if (!res->updateFromMatchPairs(cx, input, *matches)) return RegExpRunStatus_Error; } else { - res->updateLazily(cx, input, &re, searchIndex); + res->updateLazily(cx, input, re, searchIndex); } } return status; @@ -193,7 +194,7 @@ js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle ScopedMatchPairs matches(&cx->tempLifoAlloc()); - RegExpRunStatus status = ExecuteRegExpImpl(cx, res, *shared, input, *lastIndex, + RegExpRunStatus status = ExecuteRegExpImpl(cx, res, &shared, input, *lastIndex, &matches, nullptr); if (status == RegExpRunStatus_Error) return false; @@ -1036,7 +1037,7 @@ ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string, } /* Steps 3, 11-14, except 12.a.i, 12.c.i.1. */ - RegExpRunStatus status = ExecuteRegExpImpl(cx, res, *re, input, lastIndex, matches, endIndex); + RegExpRunStatus status = ExecuteRegExpImpl(cx, res, &re, input, lastIndex, matches, endIndex); if (status == RegExpRunStatus_Error) return RegExpRunStatus_Error; diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp index f3db7c1847..3ac57eccc9 100644 --- a/js/src/irregexp/RegExpEngine.cpp +++ b/js/src/irregexp/RegExpEngine.cpp @@ -1259,7 +1259,7 @@ IsNativeRegExpEnabled(JSContext* cx) } RegExpCode -irregexp::CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData* data, +irregexp::CompilePattern(JSContext* cx, HandleRegExpShared shared, RegExpCompileData* data, HandleLinearString sample, bool is_global, bool ignore_case, bool is_ascii, bool match_only, bool force_bytecode, bool sticky, bool unicode) diff --git a/js/src/irregexp/RegExpEngine.h b/js/src/irregexp/RegExpEngine.h index 22e9d944a4..6b3f6afc2a 100644 --- a/js/src/irregexp/RegExpEngine.h +++ b/js/src/irregexp/RegExpEngine.h @@ -103,7 +103,7 @@ struct RegExpCode }; RegExpCode -CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData* data, +CompilePattern(JSContext* cx, HandleRegExpShared shared, RegExpCompileData* data, HandleLinearString sample, bool is_global, bool ignore_case, bool is_ascii, bool match_only, bool force_bytecode, bool sticky, bool unicode); diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index 30f5ec14d8..c9932a0bb8 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -448,7 +448,8 @@ CrossCompartmentWrapper::regexp_toShared(JSContext* cx, HandleObject wrapper, } // Get an equivalent RegExpShared associated with the current compartment. - return cx->compartment()->regExps.get(cx, re->getSource(), re->getFlags(), shared); + RootedAtom source(cx, re->getSource()); + return cx->compartment()->regExps.get(cx, source, re->getFlags(), shared); } bool diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index cd085efb69..556b2e4413 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -283,7 +283,8 @@ RegExpObject::createShared(JSContext* cx, Handle regexp, MutableHandleRegExpShared shared) { MOZ_ASSERT(!regexp->hasShared()); - if (!cx->compartment()->regExps.get(cx, regexp->getSource(), regexp->getFlags(), shared)) + RootedAtom source(cx, regexp->getSource()); + if (!cx->compartment()->regExps.get(cx, source, regexp->getFlags(), shared)) return false; regexp->setShared(*shared); @@ -507,14 +508,15 @@ RegExpObject::toString(JSContext* cx) const } #ifdef DEBUG -bool -RegExpShared::dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input) +/* static */ bool +RegExpShared::dumpBytecode(JSContext* cx, MutableHandleRegExpShared re, bool match_only, + HandleLinearString input) { CompilationMode mode = match_only ? MatchOnly : Normal; - if (!compileIfNecessary(cx, input, mode, ForceByteCode)) + if (!RegExpShared::compileIfNecessary(cx, re, input, mode, ForceByteCode)) return false; - const uint8_t* byteCode = compilation(mode, input->hasLatin1Chars()).byteCode; + const uint8_t* byteCode = re->compilation(mode, input->hasLatin1Chars()).byteCode; const uint8_t* pc = byteCode; auto Load32Aligned = [](const uint8_t* pc) -> int32_t { @@ -897,7 +899,7 @@ RegExpObject::dumpBytecode(JSContext* cx, Handle regexp, if (!getShared(cx, regexp, &shared)) return false; - return shared->dumpBytecode(cx, match_only, input); + return RegExpShared::dumpBytecode(cx, &shared, match_only, input); } #endif @@ -976,21 +978,23 @@ RegExpShared::discardJitCode() comp.jitCode = nullptr; } -bool -RegExpShared::compile(JSContext* cx, HandleLinearString input, +/* static */ bool +RegExpShared::compile(JSContext* cx, MutableHandleRegExpShared re, HandleLinearString input, CompilationMode mode, ForceByteCodeEnum force) { TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); AutoTraceLog logCompile(logger, TraceLogger_IrregexpCompile); - RootedAtom pattern(cx, source); - return compile(cx, pattern, input, mode, force); + RootedAtom pattern(cx, re->source); + return compile(cx, re, pattern, input, mode, force); } -bool -RegExpShared::initializeNamedCaptures(JSContext* cx, irregexp::CharacterVectorVector* names, irregexp::IntegerVector* indices) +/* static */ bool +RegExpShared::initializeNamedCaptures(JSContext* cx, HandleRegExpShared re, + irregexp::CharacterVectorVector* names, + irregexp::IntegerVector* indices) { - MOZ_ASSERT(!groupsTemplate_); + MOZ_ASSERT(!re->groupsTemplate_); MOZ_ASSERT(names); MOZ_ASSERT(indices); MOZ_ASSERT(names->length() == indices->length()); @@ -1032,17 +1036,17 @@ RegExpShared::initializeNamedCaptures(JSContext* cx, irregexp::CharacterVectorVe AddTypePropertyId(cx, templateObject, id, TypeSet::Int32Type()); } - groupsTemplate_ = templateObject; - numNamedCaptures_ = numNamedCaptures; + re->groupsTemplate_ = templateObject; + re->numNamedCaptures_ = numNamedCaptures; return true; } -bool -RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString input, - CompilationMode mode, ForceByteCodeEnum force) +/* static */ bool +RegExpShared::compile(JSContext* cx, MutableHandleRegExpShared re, HandleAtom pattern, + HandleLinearString input, CompilationMode mode, ForceByteCodeEnum force) { - if (!ignoreCase() && !StringHasRegExpMetaChars(pattern)) - canStringMatch = true; + if (!re->ignoreCase() && !StringHasRegExpMetaChars(pattern)) + re->canStringMatch = true; CompileOptions options(cx); TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr); @@ -1052,34 +1056,36 @@ RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString inpu /* Parse the pattern. */ irregexp::RegExpCompileData data; if (!irregexp::ParsePattern(dummyTokenStream, cx->tempLifoAlloc(), pattern, - multiline(), mode == MatchOnly, unicode(), ignoreCase(), - global(), sticky(), dotAll(), &data)) + re->multiline(), mode == MatchOnly, re->unicode(), + re->ignoreCase(), re->global(), re->sticky(), + re->dotAll(), &data)) { return false; } - this->parenCount = data.capture_count; + re->parenCount = data.capture_count; if (data.capture_name_list) { // convert LifoAlloc'd named capture info to NativeObject - if (!initializeNamedCaptures(cx, data.capture_name_list, data.capture_index_list)) { + if (!initializeNamedCaptures(cx, re, data.capture_name_list, data.capture_index_list)) { return false; } } - irregexp::RegExpCode code = irregexp::CompilePattern(cx, this, &data, input, + irregexp::RegExpCode code = irregexp::CompilePattern(cx, re, &data, input, false /* global() */, - ignoreCase(), + re->ignoreCase(), input->hasLatin1Chars(), mode == MatchOnly, force == ForceByteCode, - sticky(), unicode()); + re->sticky(), + re->unicode()); if (code.empty()) return false; MOZ_ASSERT(!code.jitCode || !code.byteCode); MOZ_ASSERT_IF(force == ForceByteCode, code.byteCode); - RegExpCompilation& compilation = this->compilation(mode, input->hasLatin1Chars()); + RegExpCompilation& compilation = re->compilation(mode, input->hasLatin1Chars()); if (code.jitCode) compilation.jitCode = code.jitCode; else if (code.byteCode) @@ -1088,18 +1094,19 @@ RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString inpu return true; } -bool -RegExpShared::compileIfNecessary(JSContext* cx, HandleLinearString input, - CompilationMode mode, ForceByteCodeEnum force) +/* static */ bool +RegExpShared::compileIfNecessary(JSContext* cx, MutableHandleRegExpShared re, + HandleLinearString input, CompilationMode mode, + ForceByteCodeEnum force) { - if (isCompiled(mode, input->hasLatin1Chars(), force)) + if (re->isCompiled(mode, input->hasLatin1Chars(), force)) return true; - return compile(cx, input, mode, force); + return compile(cx, re, input, mode, force); } -RegExpRunStatus -RegExpShared::execute(JSContext* cx, HandleLinearString input, size_t start, - MatchPairs* matches, size_t* endIndex) +/* static */ RegExpRunStatus +RegExpShared::execute(JSContext* cx, MutableHandleRegExpShared re, HandleLinearString input, + size_t start, MatchPairs* matches, size_t* endIndex) { MOZ_ASSERT_IF(matches, !endIndex); MOZ_ASSERT_IF(!matches, endIndex); @@ -1108,14 +1115,14 @@ RegExpShared::execute(JSContext* cx, HandleLinearString input, size_t start, CompilationMode mode = matches ? Normal : MatchOnly; /* Compile the code at point-of-use. */ - if (!compileIfNecessary(cx, input, mode, DontForceByteCode)) + if (!compileIfNecessary(cx, re, input, mode, DontForceByteCode)) return RegExpRunStatus_Error; /* * Ensure sufficient memory for output vector. * No need to initialize it. The RegExp engine fills them in on a match. */ - if (matches && !matches->allocOrExpandArray(pairCount())) { + if (matches && !matches->allocOrExpandArray(re->pairCount())) { ReportOutOfMemory(cx); return RegExpRunStatus_Error; } @@ -1125,14 +1132,14 @@ RegExpShared::execute(JSContext* cx, HandleLinearString input, size_t start, // Reset the Irregexp backtrack stack if it grows during execution. irregexp::RegExpStackScope stackScope(cx->runtime()); - if (canStringMatch) { - MOZ_ASSERT(pairCount() == 1); - size_t sourceLength = source->length(); - if (sticky()) { + if (re->canStringMatch) { + MOZ_ASSERT(re->pairCount() == 1); + size_t sourceLength = re->source->length(); + if (re->sticky()) { // First part checks size_t overflow. if (sourceLength + start < sourceLength || sourceLength + start > length) return RegExpRunStatus_Success_NotFound; - if (!HasSubstringAt(input, source, start)) + if (!HasSubstringAt(input, re->source, start)) return RegExpRunStatus_Success_NotFound; if (matches) { @@ -1146,7 +1153,7 @@ RegExpShared::execute(JSContext* cx, HandleLinearString input, size_t start, return RegExpRunStatus_Success; } - int res = StringFindPattern(input, source, start); + int res = StringFindPattern(input, re->source, start); if (res == -1) return RegExpRunStatus_Success_NotFound; @@ -1162,7 +1169,7 @@ RegExpShared::execute(JSContext* cx, HandleLinearString input, size_t start, } do { - jit::JitCode* code = compilation(mode, input->hasLatin1Chars()).jitCode; + jit::JitCode* code = re->compilation(mode, input->hasLatin1Chars()).jitCode; if (!code) break; @@ -1201,10 +1208,10 @@ RegExpShared::execute(JSContext* cx, HandleLinearString input, size_t start, } while (false); // Compile bytecode for the RegExp if necessary. - if (!compileIfNecessary(cx, input, mode, ForceByteCode)) + if (!compileIfNecessary(cx, re, input, mode, ForceByteCode)) return RegExpRunStatus_Error; - uint8_t* byteCode = compilation(mode, input->hasLatin1Chars()).byteCode; + uint8_t* byteCode = re->compilation(mode, input->hasLatin1Chars()).byteCode; AutoTraceLog logInterpreter(logger, TraceLogger_IrregexpExecute); AutoStableStringChars inputChars(cx); @@ -1353,7 +1360,7 @@ RegExpCompartment::sweep(JSRuntime* rt) } bool -RegExpCompartment::get(JSContext* cx, JSAtom* source, RegExpFlag flags, +RegExpCompartment::get(JSContext* cx, HandleAtom source, RegExpFlag flags, MutableHandleRegExpShared result) { DependentAddPtr p(cx, set_.get(), Key(source, flags)); diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index 41f5e623ae..89942c6fd5 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -42,6 +42,10 @@ class MatchPairs; class RegExpShared; class RegExpStatics; +using RootedRegExpShared = JS::Rooted; +using HandleRegExpShared = JS::Handle; +using MutableHandleRegExpShared = JS::MutableHandle; + namespace frontend { class TokenStream; } enum RegExpFlag : uint8_t @@ -150,13 +154,14 @@ class RegExpShared : public gc::TenuredCell /* Internal functions. */ RegExpShared(JSAtom* source, RegExpFlag flags); - bool compile(JSContext* cx, HandleLinearString input, - CompilationMode mode, ForceByteCodeEnum force); - bool compile(JSContext* cx, HandleAtom pattern, HandleLinearString input, - CompilationMode mode, ForceByteCodeEnum force); + static bool compile(JSContext* cx, MutableHandleRegExpShared res, HandleLinearString input, + CompilationMode mode, ForceByteCodeEnum force); + static bool compile(JSContext* cx, MutableHandleRegExpShared res, HandleAtom pattern, + HandleLinearString input, CompilationMode mode, ForceByteCodeEnum force); - bool compileIfNecessary(JSContext* cx, HandleLinearString input, - CompilationMode mode, ForceByteCodeEnum force); + static bool compileIfNecessary(JSContext* cx, MutableHandleRegExpShared res, + HandleLinearString input, CompilationMode mode, + ForceByteCodeEnum force); const RegExpCompilation& compilation(CompilationMode mode, bool latin1) const { return compilationArray[CompilationIndex(mode, latin1)]; @@ -171,8 +176,9 @@ class RegExpShared : public gc::TenuredCell // Execute this RegExp on input starting from searchIndex, filling in // matches if specified and otherwise only determining if there is a match. - RegExpRunStatus execute(JSContext* cx, HandleLinearString input, size_t searchIndex, - MatchPairs* matches, size_t* endIndex); + static RegExpRunStatus execute(JSContext* cx, MutableHandleRegExpShared res, + HandleLinearString input, size_t searchIndex, + MatchPairs* matches, size_t* endIndex); // Register a table with this RegExpShared, and take ownership. bool addTable(uint8_t* table) { @@ -190,7 +196,9 @@ class RegExpShared : public gc::TenuredCell size_t pairCount() const { return getParenCount() + 1; } // not public due to circular inclusion problems - bool initializeNamedCaptures(JSContext* cx, irregexp::CharacterVectorVector* names, irregexp::IntegerVector* indices); + static bool initializeNamedCaptures(JSContext* cx, HandleRegExpShared re, + irregexp::CharacterVectorVector* names, + irregexp::IntegerVector* indices); PlainObject* getGroupsTemplate() { return groupsTemplate_; } uint32_t numNamedCaptures() const { return numNamedCaptures_; } @@ -245,14 +253,11 @@ class RegExpShared : public gc::TenuredCell size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); #ifdef DEBUG - bool dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input); + static bool dumpBytecode(JSContext* cx, MutableHandleRegExpShared res, bool match_only, + HandleLinearString input); #endif }; -using RootedRegExpShared = JS::Rooted; -using HandleRegExpShared = JS::Handle; -using MutableHandleRegExpShared = JS::MutableHandle; - class RegExpCompartment { struct Key { @@ -323,7 +328,7 @@ class RegExpCompartment bool empty() { return set_.empty(); } - bool get(JSContext* cx, JSAtom* source, RegExpFlag flags, MutableHandleRegExpShared shared); + bool get(JSContext* cx, HandleAtom source, RegExpFlag flags, MutableHandleRegExpShared shared); /* Like 'get', but compile 'maybeOpt' (if non-null). */ bool get(JSContext* cx, HandleAtom source, JSString* maybeOpt, diff --git a/js/src/vm/RegExpStatics.cpp b/js/src/vm/RegExpStatics.cpp index 27bc988db6..7073e084fd 100644 --- a/js/src/vm/RegExpStatics.cpp +++ b/js/src/vm/RegExpStatics.cpp @@ -81,7 +81,8 @@ RegExpStatics::executeLazy(JSContext* cx) /* Retrieve or create the RegExpShared in this compartment. */ RootedRegExpShared shared(cx); - if (!cx->compartment()->regExps.get(cx, lazySource, lazyFlags, &shared)) + RootedAtom source(cx, lazySource); + if (!cx->compartment()->regExps.get(cx, source, lazyFlags, &shared)) return false; /* @@ -91,7 +92,8 @@ RegExpStatics::executeLazy(JSContext* cx) /* Execute the full regular expression. */ RootedLinearString input(cx, matchesInput); - RegExpRunStatus status = shared->execute(cx, input, lazyIndex, &this->matches, nullptr); + RegExpRunStatus status = RegExpShared::execute(cx, &shared, input, lazyIndex, &this->matches, + nullptr); if (status == RegExpRunStatus_Error) return false;