mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1077514 - Execute regexps in the bytecode interpreter if the initial JIT execution was interrupted, r=jandem.
This commit is contained in:
parent
20095be902
commit
71f28b167a
@ -1650,7 +1650,7 @@ IsNativeRegExpEnabled(JSContext *cx)
|
||||
RegExpCode
|
||||
irregexp::CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
|
||||
HandleLinearString sample, bool is_global, bool ignore_case,
|
||||
bool is_ascii, bool match_only)
|
||||
bool is_ascii, bool match_only, bool force_bytecode)
|
||||
{
|
||||
if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) {
|
||||
JS_ReportError(cx, "regexp too big");
|
||||
@ -1727,7 +1727,7 @@ irregexp::CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData
|
||||
Maybe<InterpretedRegExpMacroAssembler> interpreted_assembler;
|
||||
|
||||
RegExpMacroAssembler *assembler;
|
||||
if (IsNativeRegExpEnabled(cx)) {
|
||||
if (IsNativeRegExpEnabled(cx) && !force_bytecode) {
|
||||
NativeRegExpMacroAssembler::Mode mode =
|
||||
is_ascii ? NativeRegExpMacroAssembler::ASCII
|
||||
: NativeRegExpMacroAssembler::CHAR16;
|
||||
|
@ -88,7 +88,7 @@ struct RegExpCode
|
||||
RegExpCode
|
||||
CompilePattern(JSContext *cx, RegExpShared *shared, RegExpCompileData *data,
|
||||
HandleLinearString sample, bool is_global, bool ignore_case,
|
||||
bool is_ascii, bool match_only);
|
||||
bool is_ascii, bool match_only, bool force_bytecode);
|
||||
|
||||
// Note: this may return RegExpRunStatus_Error if an interrupt was requested
|
||||
// while the code was executing.
|
||||
|
@ -455,14 +455,15 @@ RegExpShared::trace(JSTracer *trc)
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpShared::compile(JSContext *cx, HandleLinearString input, CompilationMode mode)
|
||||
RegExpShared::compile(JSContext *cx, HandleLinearString input,
|
||||
CompilationMode mode, ForceByteCodeEnum force)
|
||||
{
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logCompile(logger, TraceLogger::IrregexpCompile);
|
||||
|
||||
if (!sticky()) {
|
||||
RootedAtom pattern(cx, source);
|
||||
return compile(cx, pattern, input, mode);
|
||||
return compile(cx, pattern, input, mode, force);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -485,12 +486,12 @@ RegExpShared::compile(JSContext *cx, HandleLinearString input, CompilationMode m
|
||||
if (!fakeySource)
|
||||
return false;
|
||||
|
||||
return compile(cx, fakeySource, input, mode);
|
||||
return compile(cx, fakeySource, input, mode, force);
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpShared::compile(JSContext *cx, HandleAtom pattern, HandleLinearString input,
|
||||
CompilationMode mode)
|
||||
CompilationMode mode, ForceByteCodeEnum force)
|
||||
{
|
||||
if (!ignoreCase() && !StringHasRegExpMetaChars(pattern)) {
|
||||
canStringMatch = true;
|
||||
@ -517,25 +518,30 @@ RegExpShared::compile(JSContext *cx, HandleAtom pattern, HandleLinearString inpu
|
||||
false /* global() */,
|
||||
ignoreCase(),
|
||||
input->hasLatin1Chars(),
|
||||
mode == MatchOnly);
|
||||
mode == MatchOnly,
|
||||
force == ForceByteCode);
|
||||
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());
|
||||
if (code.jitCode)
|
||||
compilation.jitCode = code.jitCode;
|
||||
else if (code.byteCode)
|
||||
compilation.byteCode = code.byteCode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpShared::compileIfNecessary(JSContext *cx, HandleLinearString input, CompilationMode mode)
|
||||
RegExpShared::compileIfNecessary(JSContext *cx, HandleLinearString input,
|
||||
CompilationMode mode, ForceByteCodeEnum force)
|
||||
{
|
||||
if (isCompiled(mode, input->hasLatin1Chars()) || canStringMatch)
|
||||
if (isCompiled(mode, input->hasLatin1Chars(), force) || canStringMatch)
|
||||
return true;
|
||||
return compile(cx, input, mode);
|
||||
return compile(cx, input, mode, force);
|
||||
}
|
||||
|
||||
RegExpRunStatus
|
||||
@ -547,7 +553,7 @@ 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))
|
||||
if (!compileIfNecessary(cx, input, mode, DontForceByteCode))
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
/*
|
||||
@ -591,7 +597,63 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
|
||||
return RegExpRunStatus_Success;
|
||||
}
|
||||
|
||||
if (uint8_t *byteCode = compilation(mode, input->hasLatin1Chars()).byteCode) {
|
||||
do {
|
||||
jit::JitCode *code = compilation(mode, input->hasLatin1Chars()).jitCode;
|
||||
if (!code)
|
||||
break;
|
||||
|
||||
RegExpRunStatus result;
|
||||
{
|
||||
AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
|
||||
AutoCheckCannotGC nogc;
|
||||
if (input->hasLatin1Chars()) {
|
||||
const Latin1Char *chars = input->latin1Chars(nogc) + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
|
||||
} else {
|
||||
const char16_t *chars = input->twoByteChars(nogc) + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == RegExpRunStatus_Error) {
|
||||
// The RegExp engine might exit with an exception if an interrupt
|
||||
// was requested. If this happens, break out and retry the regexp
|
||||
// in the bytecode interpreter, which can execute while tolerating
|
||||
// future interrupts. Otherwise, if we keep getting interrupted we
|
||||
// will never finish executing the regexp.
|
||||
bool interrupted;
|
||||
{
|
||||
JSRuntime::AutoLockForInterrupt lock(cx->runtime());
|
||||
interrupted = cx->runtime()->interrupt;
|
||||
}
|
||||
|
||||
if (interrupted) {
|
||||
if (!InvokeInterruptCallback(cx))
|
||||
return RegExpRunStatus_Error;
|
||||
break;
|
||||
}
|
||||
|
||||
js_ReportOverRecursed(cx);
|
||||
return RegExpRunStatus_Error;
|
||||
}
|
||||
|
||||
if (result == RegExpRunStatus_Success_NotFound)
|
||||
return RegExpRunStatus_Success_NotFound;
|
||||
|
||||
MOZ_ASSERT(result == RegExpRunStatus_Success);
|
||||
|
||||
if (matches) {
|
||||
matches->displace(displacement);
|
||||
matches->checkAgainst(origLength);
|
||||
}
|
||||
return RegExpRunStatus_Success;
|
||||
} while (false);
|
||||
|
||||
// Compile bytecode for the RegExp if necessary.
|
||||
if (!compileIfNecessary(cx, input, mode, ForceByteCode))
|
||||
return RegExpRunStatus_Error;
|
||||
|
||||
uint8_t *byteCode = compilation(mode, input->hasLatin1Chars()).byteCode;
|
||||
AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
|
||||
|
||||
AutoStableStringChars inputChars(cx);
|
||||
@ -612,55 +674,6 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
|
||||
matches->checkAgainst(origLength);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
RegExpRunStatus result;
|
||||
{
|
||||
AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
|
||||
AutoCheckCannotGC nogc;
|
||||
jit::JitCode *code = compilation(mode, input->hasLatin1Chars()).jitCode;
|
||||
if (input->hasLatin1Chars()) {
|
||||
const Latin1Char *chars = input->latin1Chars(nogc) + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
|
||||
} else {
|
||||
const char16_t *chars = input->twoByteChars(nogc) + charsOffset;
|
||||
result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == RegExpRunStatus_Error) {
|
||||
// The RegExp engine might exit with an exception if an interrupt
|
||||
// was requested. Check this case and retry until a clean result is
|
||||
// obtained.
|
||||
bool interrupted;
|
||||
{
|
||||
JSRuntime::AutoLockForInterrupt lock(cx->runtime());
|
||||
interrupted = cx->runtime()->interrupt;
|
||||
}
|
||||
|
||||
if (interrupted) {
|
||||
if (!InvokeInterruptCallback(cx))
|
||||
return RegExpRunStatus_Error;
|
||||
continue;
|
||||
}
|
||||
|
||||
js_ReportOverRecursed(cx);
|
||||
return RegExpRunStatus_Error;
|
||||
}
|
||||
|
||||
if (result == RegExpRunStatus_Success_NotFound)
|
||||
return RegExpRunStatus_Success_NotFound;
|
||||
|
||||
MOZ_ASSERT(result == RegExpRunStatus_Success);
|
||||
break;
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
matches->displace(displacement);
|
||||
matches->checkAgainst(origLength);
|
||||
}
|
||||
return RegExpRunStatus_Success;
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -106,6 +106,11 @@ class RegExpShared
|
||||
MatchOnly
|
||||
};
|
||||
|
||||
enum ForceByteCodeEnum {
|
||||
DontForceByteCode,
|
||||
ForceByteCode
|
||||
};
|
||||
|
||||
private:
|
||||
friend class RegExpCompartment;
|
||||
friend class RegExpStatics;
|
||||
@ -120,7 +125,9 @@ class RegExpShared
|
||||
RegExpCompilation() : byteCode(nullptr) {}
|
||||
~RegExpCompilation() { js_free(byteCode); }
|
||||
|
||||
bool compiled() const { return jitCode || byteCode; }
|
||||
bool compiled(ForceByteCodeEnum force = DontForceByteCode) const {
|
||||
return byteCode || (force == DontForceByteCode && jitCode);
|
||||
}
|
||||
};
|
||||
|
||||
/* Source to the RegExp, for lazy compilation. */
|
||||
@ -145,10 +152,13 @@ class RegExpShared
|
||||
Vector<uint8_t *, 0, SystemAllocPolicy> tables;
|
||||
|
||||
/* Internal functions. */
|
||||
bool compile(JSContext *cx, HandleLinearString input, CompilationMode mode);
|
||||
bool compile(JSContext *cx, HandleAtom pattern, HandleLinearString input, CompilationMode mode);
|
||||
bool compile(JSContext *cx, HandleLinearString input,
|
||||
CompilationMode mode, ForceByteCodeEnum force);
|
||||
bool compile(JSContext *cx, HandleAtom pattern, HandleLinearString input,
|
||||
CompilationMode mode, ForceByteCodeEnum force);
|
||||
|
||||
bool compileIfNecessary(JSContext *cx, HandleLinearString input, CompilationMode mode);
|
||||
bool compileIfNecessary(JSContext *cx, HandleLinearString input,
|
||||
CompilationMode mode, ForceByteCodeEnum force);
|
||||
|
||||
const RegExpCompilation &compilation(CompilationMode mode, bool latin1) const {
|
||||
return compilationArray[CompilationIndex(mode, latin1)];
|
||||
@ -189,8 +199,9 @@ class RegExpShared
|
||||
bool multiline() const { return flags & MultilineFlag; }
|
||||
bool sticky() const { return flags & StickyFlag; }
|
||||
|
||||
bool isCompiled(CompilationMode mode, bool latin1) const {
|
||||
return compilation(mode, latin1).compiled();
|
||||
bool isCompiled(CompilationMode mode, bool latin1,
|
||||
ForceByteCodeEnum force = DontForceByteCode) const {
|
||||
return compilation(mode, latin1).compiled(force);
|
||||
}
|
||||
bool isCompiled() const {
|
||||
return isCompiled(Normal, true) || isCompiled(Normal, false)
|
||||
|
Loading…
Reference in New Issue
Block a user