Commit 71acda22 authored by Ana Peško's avatar Ana Peško Committed by Commit Bot

[regexp] Naive tiering-up

This CL implements a naive tiering-up strategy where the interpreter
is used for the first execution for every regex, and the compiler is
used for every execution after that. The only exception is if a
global replace is being executed on a regex, we eagerly tier-up to
native code right away.

To use the tier-up logic --regexp-tier-up needs to be set. It is
currently disabled by default.

Bug v8:9566

Change-Id: Ib64ed77cbfcde10411161c0541dfa2501a0a93bd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1710661Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Ana Pesko <anapesko@google.com>
Cr-Commit-Position: refs/heads/master@{#63150}
parent 46a2b441
......@@ -555,7 +555,11 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
BIND(&interpreted);
{
TNode<ByteArray> byte_code = CAST(var_code.value());
// Tier-up in runtime to compiler if ticks are non-zero.
TNode<Smi> ticks = CAST(
UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpTierUpTicksIndex));
GotoIf(TruncateIntPtrToInt32(BitcastTaggedSignedToWord(ticks)), &runtime);
IncrementCounter(isolate()->counters()->regexp_entry_native(), 1);
// Set up args for the final call into IrregexpInterpreter.
......@@ -571,9 +575,9 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
MachineType arg0_type = type_ptr;
TNode<ExternalReference> arg0 = isolate_address;
// Argument 1: Pattern ByteCode.
// Argument 1: Regular expression object.
MachineType arg1_type = type_tagged;
TNode<ByteArray> arg1 = byte_code;
TNode<JSRegExp> arg1 = regexp;
// Argument 2: Original subject string.
MachineType arg2_type = type_tagged;
......
......@@ -1450,7 +1450,8 @@ void JSRegExp::JSRegExpVerify(Isolate* isolate) {
break;
}
case JSRegExp::IRREGEXP: {
bool is_native = RegExp::GeneratesNativeCode();
bool can_be_native = RegExp::CanGenerateNativeCode();
bool can_be_interpreted = RegExp::CanGenerateBytecode();
FixedArray arr = FixedArray::cast(data());
Object one_byte_data = arr.get(JSRegExp::kIrregexpLatin1CodeIndex);
......@@ -1458,14 +1459,17 @@ void JSRegExp::JSRegExpVerify(Isolate* isolate) {
// Code/ByteArray: Compiled code.
CHECK((one_byte_data.IsSmi() &&
Smi::ToInt(one_byte_data) == JSRegExp::kUninitializedValue) ||
(is_native ? one_byte_data.IsCode() : one_byte_data.IsByteArray()));
(can_be_interpreted && one_byte_data.IsByteArray()) ||
(can_be_native && one_byte_data.IsCode()));
Object uc16_data = arr.get(JSRegExp::kIrregexpUC16CodeIndex);
CHECK((uc16_data.IsSmi() &&
Smi::ToInt(uc16_data) == JSRegExp::kUninitializedValue) ||
(is_native ? uc16_data.IsCode() : uc16_data.IsByteArray()));
(can_be_interpreted && uc16_data.IsByteArray()) ||
(can_be_native && uc16_data.IsCode()));
CHECK(arr.get(JSRegExp::kIrregexpCaptureCountIndex).IsSmi());
CHECK(arr.get(JSRegExp::kIrregexpMaxRegisterCountIndex).IsSmi());
CHECK(arr.get(JSRegExp::kIrregexpTierUpTicksIndex).IsSmi());
break;
}
default:
......
......@@ -1245,6 +1245,9 @@ DEFINE_UINT(serialization_chunk_size, 4096,
DEFINE_BOOL(regexp_optimization, true, "generate optimized regexp code")
DEFINE_BOOL(regexp_mode_modifiers, false, "enable inline flags in regexp.")
DEFINE_BOOL(regexp_interpret_all, false, "interpret all regexp code")
DEFINE_BOOL(regexp_tier_up, false,
"enable regexp interpreter and tier up to the compiler")
DEFINE_NEG_IMPLICATION(regexp_interpret_all, regexp_tier_up)
// Testing flags test/cctest/test-{flags,api,serialization}.cc
DEFINE_BOOL(testing_bool_flag, true, "testing_bool_flag")
......@@ -1383,6 +1386,7 @@ DEFINE_BOOL(trace_regexp_bytecodes, false, "trace regexp bytecode execution")
DEFINE_BOOL(trace_regexp_assembler, false,
"trace regexp macro assembler calls.")
DEFINE_BOOL(trace_regexp_parser, false, "trace regexp parsing")
DEFINE_BOOL(trace_regexp_tier_up, false, "trace regexp tiering up execution")
// Debugger
DEFINE_BOOL(print_break_location, false, "print source location on debug break")
......
......@@ -3901,6 +3901,7 @@ void Factory::SetRegExpIrregexpData(Handle<JSRegExp> regexp,
store->set(JSRegExp::kIrregexpMaxRegisterCountIndex, Smi::kZero);
store->set(JSRegExp::kIrregexpCaptureCountIndex, Smi::FromInt(capture_count));
store->set(JSRegExp::kIrregexpCaptureNameMapIndex, uninitialized);
store->set(JSRegExp::kIrregexpTierUpTicksIndex, Smi::kZero);
regexp->set_data(*store);
}
......
......@@ -98,6 +98,10 @@ class JSRegExp : public JSObject {
Handle<String> source,
Handle<String> flags_string);
bool MarkedForTierUp();
void ResetTierUp();
void MarkTierUpForNextExec();
inline Type TypeTag() const;
// Number of captures (without the match itself).
inline int CaptureCount();
......@@ -116,6 +120,9 @@ class JSRegExp : public JSObject {
}
}
// This could be a Smi kUninitializedValue, a ByteArray, or Code.
Object Code(bool is_latin1) const;
bool ShouldProduceBytecode();
inline bool HasCompiledCode() const;
inline void DiscardCompiledCodeForSerialization();
......@@ -160,8 +167,9 @@ class JSRegExp : public JSObject {
// Maps names of named capture groups (at indices 2i) to their corresponding
// (1-based) capture group indices (at indices 2i + 1).
static const int kIrregexpCaptureNameMapIndex = kDataIndex + 4;
static const int kIrregexpTierUpTicksIndex = kDataIndex + 5;
static const int kIrregexpDataSize = kIrregexpCaptureNameMapIndex + 1;
static const int kIrregexpDataSize = kIrregexpTierUpTicksIndex + 1;
// In-object fields.
static const int kLastIndexFieldIndex = 0;
......
......@@ -6146,6 +6146,39 @@ Handle<JSRegExp> JSRegExp::Copy(Handle<JSRegExp> regexp) {
return Handle<JSRegExp>::cast(isolate->factory()->CopyJSObject(regexp));
}
Object JSRegExp::Code(bool is_latin1) const {
return DataAt(code_index(is_latin1));
}
bool JSRegExp::ShouldProduceBytecode() {
return FLAG_regexp_interpret_all ||
(FLAG_regexp_tier_up && !MarkedForTierUp());
}
// An irregexp is considered to be marked for tier up if the tier-up ticks value
// is not zero. An atom is not subject to tier-up implementation, so the tier-up
// ticks value is not set.
bool JSRegExp::MarkedForTierUp() {
DCHECK(data().IsFixedArray());
if (TypeTag() == JSRegExp::ATOM) {
return false;
}
return Smi::ToInt(DataAt(kIrregexpTierUpTicksIndex)) != 0;
}
void JSRegExp::ResetTierUp() {
DCHECK(FLAG_regexp_tier_up);
DCHECK_EQ(TypeTag(), JSRegExp::IRREGEXP);
FixedArray::cast(data()).set(JSRegExp::kIrregexpTierUpTicksIndex, Smi::kZero);
}
void JSRegExp::MarkTierUpForNextExec() {
DCHECK(FLAG_regexp_tier_up);
DCHECK_EQ(TypeTag(), JSRegExp::IRREGEXP);
FixedArray::cast(data()).set(JSRegExp::kIrregexpTierUpTicksIndex,
Smi::FromInt(1));
}
namespace {
template <typename Char>
......
......@@ -8,6 +8,7 @@
#include "src/ast/ast.h"
#include "src/base/small-vector.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/objects-inl.h"
#include "src/regexp/regexp-bytecodes.h"
#include "src/regexp/regexp-macro-assembler.h"
......@@ -780,6 +781,20 @@ IrregexpInterpreter::Result RawMatch(Isolate* isolate, ByteArray code_array,
// static
IrregexpInterpreter::Result IrregexpInterpreter::Match(
Isolate* isolate, JSRegExp regexp, String subject_string, int* registers,
int registers_length, int start_position, RegExp::CallOrigin call_origin) {
if (FLAG_regexp_tier_up) {
regexp.MarkTierUpForNextExec();
}
bool is_one_byte = String::IsOneByteRepresentationUnderneath(subject_string);
ByteArray code_array = ByteArray::cast(regexp.Code(is_one_byte));
return MatchInternal(isolate, code_array, subject_string, registers,
registers_length, start_position, call_origin);
}
IrregexpInterpreter::Result IrregexpInterpreter::MatchInternal(
Isolate* isolate, ByteArray code_array, String subject_string,
int* registers, int registers_length, int start_position,
RegExp::CallOrigin call_origin) {
......@@ -818,7 +833,7 @@ IrregexpInterpreter::Result IrregexpInterpreter::Match(
// This method is called through an external reference from RegExpExecInternal
// builtin.
IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromJs(
Isolate* isolate, Address code, Address subject, int* registers,
Isolate* isolate, Address regexp, Address subject, int* registers,
int32_t registers_length, int32_t start_position) {
DCHECK_NOT_NULL(isolate);
DCHECK_NOT_NULL(registers);
......@@ -827,19 +842,17 @@ IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromJs(
DisallowJavascriptExecution no_js(isolate);
String subject_string = String::cast(Object(subject));
ByteArray code_array = ByteArray::cast(Object(code));
JSRegExp regexp_obj = JSRegExp::cast(Object(regexp));
return Match(isolate, code_array, subject_string, registers, registers_length,
return Match(isolate, regexp_obj, subject_string, registers, registers_length,
start_position, RegExp::CallOrigin::kFromJs);
}
IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromRuntime(
Isolate* isolate, Handle<ByteArray> code_array,
Handle<String> subject_string, int* registers, int registers_length,
int start_position) {
return Match(isolate, *code_array, *subject_string, registers,
registers_length, start_position,
RegExp::CallOrigin::kFromRuntime);
Isolate* isolate, Handle<JSRegExp> regexp, Handle<String> subject_string,
int* registers, int registers_length, int start_position) {
return Match(isolate, *regexp, *subject_string, registers, registers_length,
start_position, RegExp::CallOrigin::kFromRuntime);
}
} // namespace internal
......
......@@ -24,22 +24,26 @@ class V8_EXPORT_PRIVATE IrregexpInterpreter : public AllStatic {
// In case a StackOverflow occurs, a StackOverflowException is created and
// EXCEPTION is returned.
static Result MatchForCallFromRuntime(Isolate* isolate,
Handle<ByteArray> code_array,
Handle<JSRegExp> regexp,
Handle<String> subject_string,
int* registers, int registers_length,
int start_position);
// In case a StackOverflow occurs, EXCEPTION is returned. The caller is
// responsible for creating the exception.
static Result MatchForCallFromJs(Isolate* isolate, Address code,
static Result MatchForCallFromJs(Isolate* isolate, Address regexp,
Address subject, int* registers,
int32_t registers_length,
int32_t start_position);
static Result MatchInternal(Isolate* isolate, ByteArray code_array,
String subject_string, int* registers,
int registers_length, int start_position,
RegExp::CallOrigin call_origin);
private:
static Result Match(Isolate* isolate, ByteArray code_array,
String subject_string, int* registers,
int registers_length, int start_position,
static Result Match(Isolate* isolate, JSRegExp regexp, String subject_string,
int* registers, int registers_length, int start_position,
RegExp::CallOrigin call_origin);
};
......
......@@ -298,29 +298,68 @@ Handle<Object> RegExpImpl::AtomExec(Isolate* isolate, Handle<JSRegExp> re,
bool RegExpImpl::EnsureCompiledIrregexp(Isolate* isolate, Handle<JSRegExp> re,
Handle<String> sample_subject,
bool is_one_byte) {
Object compiled_code = re->DataAt(JSRegExp::code_index(is_one_byte));
if (compiled_code != Smi::FromInt(JSRegExp::kUninitializedValue)) {
Object compiled_code = re->Code(is_one_byte);
bool needs_initial_compilation =
compiled_code == Smi::FromInt(JSRegExp::kUninitializedValue);
// Recompile is needed when we're dealing with the first execution of the
// regexp after the decision to tier up has been made. If the tiering up
// strategy is not in use, this value is always false.
bool needs_tier_up_compilation =
re->MarkedForTierUp() && compiled_code.IsByteArray();
if (FLAG_trace_regexp_tier_up && needs_tier_up_compilation) {
PrintF("JSRegExp object %p needs tier-up compilation\n",
reinterpret_cast<void*>(re->ptr()));
}
if (!needs_initial_compilation && !needs_tier_up_compilation) {
// We expect bytecode here only if we're interpreting all regexps. In all
// other cases, we can only expect the compiled code to be native code.
DCHECK(FLAG_regexp_interpret_all ? compiled_code.IsByteArray()
: compiled_code.IsCode());
return true;
}
DCHECK_IMPLIES(needs_tier_up_compilation, compiled_code.IsByteArray());
return CompileIrregexp(isolate, re, sample_subject, is_one_byte);
}
#ifdef DEBUG
namespace {
bool RegExpCodeIsValidForPreCompilation(Handle<JSRegExp> re, bool is_one_byte) {
Object entry = re->Code(is_one_byte);
// If we're not using the tier-up strategy, entry can only be a smi
// representing an uncompiled regexp here. If we're using the tier-up
// strategy, entry can still be a smi representing an uncompiled regexp, when
// compiling the regexp before the tier-up, or it can contain previously
// compiled bytecode, when recompiling the regexp after the tier-up. If the
// tier-up was forced, which happens for global replaces, entry is a smi
// representing an uncompiled regexp, even though we're "recompiling" after
// the tier-up.
if (re->ShouldProduceBytecode()) {
DCHECK(entry.IsSmi());
int entry_value = Smi::ToInt(entry);
DCHECK_EQ(JSRegExp::kUninitializedValue, entry_value);
} else {
DCHECK(entry.IsByteArray() || entry.IsSmi());
}
return true;
}
} // namespace
#endif
bool RegExpImpl::CompileIrregexp(Isolate* isolate, Handle<JSRegExp> re,
Handle<String> sample_subject,
bool is_one_byte) {
// Compile the RegExp.
Zone zone(isolate->allocator(), ZONE_NAME);
PostponeInterruptsScope postpone(isolate);
#ifdef DEBUG
Object entry = re->DataAt(JSRegExp::code_index(is_one_byte));
// When arriving here entry can only be a smi representing an uncompiled
// regexp.
DCHECK(entry.IsSmi());
int entry_value = Smi::ToInt(entry);
DCHECK_EQ(JSRegExp::kUninitializedValue, entry_value);
#endif
DCHECK(RegExpCodeIsValidForPreCompilation(re, is_one_byte));
JSRegExp::Flags flags = re->GetFlags();
......@@ -335,6 +374,14 @@ bool RegExpImpl::CompileIrregexp(Isolate* isolate, Handle<JSRegExp> re,
USE(ThrowRegExpException(isolate, re, pattern, compile_data.error));
return false;
}
// The compilation target is a kBytecode if we're interpreting all regexp
// objects, or if we're using the tier-up strategy but the tier-up hasn't
// happened yet. The compilation target is a kNative if we're using the
// tier-up strategy and we need to recompile to tier-up, or if we're producing
// native code for all regexp objects.
compile_data.compilation_target = re->ShouldProduceBytecode()
? RegExpCompilationTarget::kBytecode
: RegExpCompilationTarget::kNative;
const bool compilation_succeeded =
Compile(isolate, &zone, &compile_data, flags, pattern, sample_subject,
is_one_byte);
......@@ -353,6 +400,15 @@ bool RegExpImpl::CompileIrregexp(Isolate* isolate, Handle<JSRegExp> re,
SetIrregexpMaxRegisterCount(*data, compile_data.register_count);
}
if (FLAG_trace_regexp_tier_up) {
PrintF("JSRegExp object %p %s size: %d\n",
reinterpret_cast<void*>(re->ptr()),
re->ShouldProduceBytecode() ? "bytecode" : "native code",
re->ShouldProduceBytecode()
? IrregexpByteCode(*data, is_one_byte).Size()
: IrregexpNativeCode(*data, is_one_byte).Size());
}
return true;
}
......@@ -411,7 +467,7 @@ int RegExp::IrregexpPrepare(Isolate* isolate, Handle<JSRegExp> regexp,
DisallowHeapAllocation no_gc;
FixedArray data = FixedArray::cast(regexp->data());
if (FLAG_regexp_interpret_all) {
if (regexp->ShouldProduceBytecode()) {
// Byte-code regexp needs space allocated for all its registers.
// The result captures are copied to the start of the registers array
// if the match succeeds. This way those registers are not clobbered
......@@ -436,7 +492,7 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle<JSRegExp> regexp,
bool is_one_byte = String::IsOneByteRepresentationUnderneath(*subject);
if (!FLAG_regexp_interpret_all) {
if (!regexp->ShouldProduceBytecode()) {
DCHECK(output_size >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2);
do {
EnsureCompiledIrregexp(isolate, regexp, subject, is_one_byte);
......@@ -464,12 +520,11 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle<JSRegExp> regexp,
// the, potentially, different subject (the string can switch between
// being internal and external, and even between being Latin1 and UC16,
// but the characters are always the same).
RegExp::IrregexpPrepare(isolate, regexp, subject);
is_one_byte = String::IsOneByteRepresentationUnderneath(*subject);
} while (true);
UNREACHABLE();
} else {
DCHECK(FLAG_regexp_interpret_all);
DCHECK(regexp->ShouldProduceBytecode());
DCHECK(output_size >= IrregexpNumberOfRegisters(*irregexp));
// We must have done EnsureCompiledIrregexp, so we can get the number of
// registers.
......@@ -478,13 +533,10 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle<JSRegExp> regexp,
int32_t* raw_output = &output[number_of_capture_registers];
do {
Handle<ByteArray> byte_codes(IrregexpByteCode(*irregexp, is_one_byte),
isolate);
IrregexpInterpreter::Result result =
IrregexpInterpreter::MatchForCallFromRuntime(
isolate, byte_codes, subject, raw_output,
number_of_capture_registers, index);
isolate, regexp, subject, raw_output, number_of_capture_registers,
index);
DCHECK_IMPLIES(result == IrregexpInterpreter::EXCEPTION,
isolate->has_pending_exception());
......@@ -500,6 +552,10 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle<JSRegExp> regexp,
case IrregexpInterpreter::RETRY:
// The string has changed representation, and we must restart the
// match.
// We need to reset the tier up to start over with compilation.
if (FLAG_regexp_tier_up) {
regexp->ResetTierUp();
}
is_one_byte = String::IsOneByteRepresentationUnderneath(*subject);
EnsureCompiledIrregexp(isolate, regexp, subject, is_one_byte);
break;
......@@ -543,6 +599,7 @@ MaybeHandle<Object> RegExpImpl::IrregexpExec(
int res =
RegExpImpl::IrregexpExecRaw(isolate, regexp, subject, previous_index,
output_registers, required_registers);
if (res == RegExp::RE_SUCCESS) {
int capture_count =
IrregexpNumberOfCaptures(FixedArray::cast(regexp->data()));
......@@ -709,7 +766,7 @@ bool RegExpImpl::Compile(Isolate* isolate, Zone* zone, RegExpCompileData* data,
// Create the correct assembler for the architecture.
std::unique_ptr<RegExpMacroAssembler> macro_assembler;
if (!FLAG_regexp_interpret_all) {
if (data->compilation_target == RegExpCompilationTarget::kNative) {
// Native regexp implementation.
DCHECK(!FLAG_jitless);
......@@ -745,8 +802,7 @@ bool RegExpImpl::Compile(Isolate* isolate, Zone* zone, RegExpCompileData* data,
#error "Unsupported architecture"
#endif
} else {
DCHECK(FLAG_regexp_interpret_all);
DCHECK_EQ(data->compilation_target, RegExpCompilationTarget::kBytecode);
// Interpreted regexp implementation.
macro_assembler.reset(new RegExpBytecodeGenerator(isolate, zone));
}
......@@ -796,7 +852,7 @@ RegExpGlobalCache::RegExpGlobalCache(Handle<JSRegExp> regexp,
regexp_(regexp),
subject_(subject),
isolate_(isolate) {
bool interpreted = FLAG_regexp_interpret_all;
bool interpreted = regexp->ShouldProduceBytecode();
if (regexp_->TypeTag() == JSRegExp::ATOM) {
static const int kAtomRegistersPerMatch = 2;
......@@ -861,6 +917,7 @@ int RegExpGlobalCache::AdvanceZeroLength(int last_index) {
int32_t* RegExpGlobalCache::FetchNext() {
current_match_index_++;
if (current_match_index_ >= num_matches_) {
// Current batch of results exhausted.
// Fail if last batch was not even fully filled.
......
......@@ -13,6 +13,8 @@ namespace internal {
class RegExpNode;
class RegExpTree;
enum class RegExpCompilationTarget : int { kBytecode, kNative };
// TODO(jgruber): Consider splitting between ParseData and CompileData.
struct RegExpCompileData {
// The parsed AST as produced by the RegExpParser.
......@@ -46,12 +48,20 @@ struct RegExpCompileData {
// The number of registers used by the generated code.
int register_count = 0;
// The compilation target (bytecode or native code).
RegExpCompilationTarget compilation_target;
};
class RegExp final : public AllStatic {
public:
// Whether the irregexp engine generates native code or interpreter bytecode.
static bool GeneratesNativeCode() { return !FLAG_regexp_interpret_all; }
static bool CanGenerateNativeCode() {
return !FLAG_regexp_interpret_all || FLAG_regexp_tier_up;
}
static bool CanGenerateBytecode() {
return FLAG_regexp_interpret_all || FLAG_regexp_tier_up;
}
// Parses the RegExp pattern and prepares the JSRegExp object with
// generic data and choice of implementation - as well as what
......
......@@ -613,6 +613,20 @@ V8_WARN_UNUSED_RESULT static Object StringReplaceGlobalRegExpWithString(
JSRegExp::Type typeTag = regexp->TypeTag();
if (typeTag == JSRegExp::IRREGEXP) {
// Force tier up to native code for global replaces. The global replace is
// implemented differently for native code and bytecode execution, where the
// native code expects an array to store all the matches, and the bytecode
// matches one at a time, so it's easier to tier-up to native code from the
// start.
if (FLAG_regexp_tier_up) {
regexp->MarkTierUpForNextExec();
if (FLAG_trace_regexp_tier_up) {
PrintF(
"Forcing tier-up of JSRegExp object %p in "
"StringReplaceGlobalRegExpWithString\n",
reinterpret_cast<void*>(regexp->ptr()));
}
}
// Ensure the RegExp is compiled so we can access the capture-name map.
if (RegExp::IrregexpPrepare(isolate, regexp, subject) == -1) {
DCHECK(isolate->has_pending_exception());
......@@ -1085,6 +1099,19 @@ static Object SearchRegExpMultiple(Isolate* isolate, Handle<String> subject,
DCHECK_NE(has_capture, regexp->CaptureCount() == 0);
DCHECK(subject->IsFlat());
// Force tier up to native code for global replaces. The global replace is
// implemented differently for native code and bytecode execution, where the
// native code expects an array to store all the matches, and the bytecode
// matches one at a time, so it's easier to tier-up to native code from the
// start.
if (FLAG_regexp_tier_up && regexp->TypeTag() == JSRegExp::IRREGEXP) {
regexp->MarkTierUpForNextExec();
if (FLAG_trace_regexp_tier_up) {
PrintF("Forcing tier-up of JSRegExp object %p in SearchRegExpMultiple\n",
reinterpret_cast<void*>(regexp->ptr()));
}
}
int capture_count = regexp->CaptureCount();
int subject_length = subject->length();
......
......@@ -518,6 +518,7 @@
'test-regexp/MacroAssemblerNativeSimpleUC16': [SKIP],
'test-regexp/MacroAssemblerNativeSuccess': [SKIP],
'test-regexp/MacroAssemblerStackOverflow': [SKIP],
'test-regexp/Graph': [SKIP],
'test-run-bytecode-graph-builder/*': [SKIP],
'test-run-calls-to-external-references/*': [SKIP],
'test-run-deopt/*': [SKIP],
......
......@@ -209,5 +209,11 @@ TEST(FlagsJitlessImplications) {
}
}
TEST(FlagsRegexpInterpretAllImplications) {
if (FLAG_regexp_interpret_all) {
CHECK(!FLAG_regexp_tier_up);
}
}
} // namespace internal
} // namespace v8
......@@ -535,6 +535,7 @@ static RegExpNode* Compile(const char* input, bool multiline, bool unicode,
Isolate* isolate = CcTest::i_isolate();
FlatStringReader reader(isolate, CStrVector(input));
RegExpCompileData compile_data;
compile_data.compilation_target = RegExpCompilationTarget::kNative;
JSRegExp::Flags flags = JSRegExp::kNone;
if (multiline) flags = JSRegExp::kMultiline;
if (unicode) flags = JSRegExp::kUnicode;
......@@ -1298,8 +1299,9 @@ TEST(MacroAssembler) {
Handle<String> f1_16 = factory->NewStringFromTwoByte(
Vector<const uc16>(str1, 6)).ToHandleChecked();
CHECK(IrregexpInterpreter::MatchForCallFromRuntime(isolate, array, f1_16,
captures, 5, 0));
CHECK(IrregexpInterpreter::MatchInternal(isolate, *array, *f1_16, captures, 5,
0,
RegExp::CallOrigin::kFromRuntime));
CHECK_EQ(0, captures[0]);
CHECK_EQ(3, captures[1]);
CHECK_EQ(1, captures[2]);
......@@ -1310,8 +1312,9 @@ TEST(MacroAssembler) {
Handle<String> f2_16 = factory->NewStringFromTwoByte(
Vector<const uc16>(str2, 6)).ToHandleChecked();
CHECK(!IrregexpInterpreter::MatchForCallFromRuntime(isolate, array, f2_16,
captures, 5, 0));
CHECK(!IrregexpInterpreter::MatchInternal(isolate, *array, *f2_16, captures,
5, 0,
RegExp::CallOrigin::kFromRuntime));
CHECK_EQ(42, captures[0]);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment