package com.oracle.truffle.regex;
import java.util.logging.Level;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.regex.tregex.util.DebugUtil;
import com.oracle.truffle.regex.tregex.util.Loggers;
public class RegexCompilerWithFallback implements RegexCompiler {
private final RegexCompiler mainCompiler;
private final RegexCompiler fallbackCompiler;
public RegexCompilerWithFallback(RegexCompiler mainCompiler, TruffleObject fallbackCompiler) {
this.mainCompiler = mainCompiler;
this.fallbackCompiler = ForeignRegexCompiler.importRegexCompiler(fallbackCompiler);
}
@Override
@CompilerDirectives.TruffleBoundary
public Object compile(RegexSource regexSource) throws RegexSyntaxException, UnsupportedRegexException {
Object regex;
long elapsedTimeMain = 0;
long elapsedTimeFallback = 0;
DebugUtil.Timer timer = null;
final boolean shouldLog = shouldLogCompilationTime();
if (shouldLog) {
timer = new DebugUtil.Timer();
}
try {
if (shouldLog) {
timer.start();
}
regex = mainCompiler.compile(regexSource);
if (shouldLog) {
elapsedTimeMain = timer.getElapsed();
}
Loggers.LOG_COMPILER_FALLBACK.finer(() -> "Primary compiler used: " + regexSource);
} catch (UnsupportedRegexException mainBailout) {
Loggers.LOG_BAILOUT_MESSAGES.fine(() -> mainBailout.getReason() + ": " + regexSource);
try {
if (shouldLog) {
timer.start();
}
regex = fallbackCompiler.compile(regexSource);
if (shouldLog) {
elapsedTimeFallback = timer.getElapsed();
}
Loggers.LOG_COMPILER_FALLBACK.fine(() -> String.format("Secondary compiler used (primary bailout due to '%s'): %s", mainBailout.getReason(), regexSource));
} catch (UnsupportedRegexException fallbackBailout) {
Loggers.LOG_COMPILER_FALLBACK.fine(() -> String.format("No compiler handled following regex (primary bailout: '%s'; secondary bailout: '%s'): %s", mainBailout.getReason(),
fallbackBailout.getReason(), regexSource));
String bailoutReasons = String.format("%s; %s", mainBailout.getReason(), fallbackBailout.getReason());
throw new UnsupportedRegexException(bailoutReasons, regexSource);
}
}
if (shouldLog) {
logCompilationTime(regexSource, elapsedTimeMain, elapsedTimeFallback);
}
return regex;
}
private static boolean shouldLogCompilationTime() {
return Loggers.LOG_TOTAL_COMPILATION_TIME.isLoggable(Level.FINE);
}
private static void logCompilationTime(RegexSource regexSource, long elapsedTimeMain, long elapsedTimeFallback) {
Loggers.LOG_TOTAL_COMPILATION_TIME.log(Level.FINE, "{0}, {1}, {2}, {3}", new Object[]{
DebugUtil.Timer.elapsedToString(elapsedTimeMain + elapsedTimeFallback),
DebugUtil.Timer.elapsedToString(elapsedTimeMain),
DebugUtil.Timer.elapsedToString(elapsedTimeFallback),
DebugUtil.jsStringEscape(regexSource.toString())
});
}
}