[regexp] Consolidate calls to jitted irregexp and regexp interpreter
The code fields in a JSRegExp object now either contain irregexp compiled code or a trampoline to the interpreter. This way the code can be executed without explicitly checking if the regexp shall be interpreted or executed natively. In case of interpreted regexp the generated bytecode is now stored in its own fields instead of the code fields for Latin1 and UC16 respectively. The signatures of the jitted irregexp match and the regexp interpreter have been equalized. Bug: v8:9516 Change-Id: I30e3d86f4702a902d3387bccc1ee91dea501fe4e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1762513 Commit-Queue: Patrick Thier <pthier@google.com> Reviewed-by: Peter Marshall <petermarshall@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#63457}
This commit is contained in:
parent
37a4937baf
commit
213504b9d7
@ -863,6 +863,7 @@ namespace internal {
|
||||
/* RegExp helpers */ \
|
||||
TFS(RegExpExecAtom, kRegExp, kString, kLastIndex, kMatchInfo) \
|
||||
TFS(RegExpExecInternal, kRegExp, kString, kLastIndex, kMatchInfo) \
|
||||
ASM(RegExpInterpreterTrampoline, CCall) \
|
||||
TFS(RegExpMatchFast, kReceiver, kPattern) \
|
||||
TFS(RegExpPrototypeExecSlow, kReceiver, kString) \
|
||||
TFS(RegExpSearchFast, kReceiver, kPattern) \
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/builtins/growable-fixed-array-gen.h"
|
||||
#include "src/codegen/code-factory.h"
|
||||
#include "src/codegen/code-stub-assembler.h"
|
||||
#include "src/codegen/macro-assembler.h"
|
||||
#include "src/execution/protectors.h"
|
||||
#include "src/heap/factory-inl.h"
|
||||
#include "src/logging/counters.h"
|
||||
@ -25,12 +26,60 @@ using compiler::Node;
|
||||
template <class T>
|
||||
using TNode = compiler::TNode<T>;
|
||||
|
||||
// Tail calls the regular expression interpreter.
|
||||
// static
|
||||
void Builtins::Generate_RegExpInterpreterTrampoline(MacroAssembler* masm) {
|
||||
ExternalReference interpreter_code_entry =
|
||||
ExternalReference::re_match_for_call_from_js(masm->isolate());
|
||||
masm->Jump(interpreter_code_entry);
|
||||
}
|
||||
|
||||
TNode<Smi> RegExpBuiltinsAssembler::SmiZero() { return SmiConstant(0); }
|
||||
|
||||
TNode<IntPtrT> RegExpBuiltinsAssembler::IntPtrZero() {
|
||||
return IntPtrConstant(0);
|
||||
}
|
||||
|
||||
// If code is a builtin, return the address to the (possibly embedded) builtin
|
||||
// code entry, otherwise return the entry of the code object itself.
|
||||
TNode<RawPtrT> RegExpBuiltinsAssembler::LoadCodeObjectEntry(TNode<Code> code) {
|
||||
TVARIABLE(RawPtrT, var_result);
|
||||
|
||||
Label if_code_is_off_heap(this), out(this);
|
||||
{
|
||||
// TODO(pthier): A potential optimization for the future is to make this
|
||||
// decision based on the builtin index instead of flags, and avoid the
|
||||
// additional load below.
|
||||
TNode<Int32T> code_flags = UncheckedCast<Int32T>(
|
||||
LoadObjectField(code, Code::kFlagsOffset, MachineType::Int32()));
|
||||
GotoIf(IsSetWord32(code_flags, Code::IsOffHeapTrampoline::kMask),
|
||||
&if_code_is_off_heap);
|
||||
var_result = ReinterpretCast<RawPtrT>(
|
||||
IntPtrAdd(BitcastTaggedToWord(code),
|
||||
IntPtrConstant(Code::kHeaderSize - kHeapObjectTag)));
|
||||
Goto(&out);
|
||||
}
|
||||
|
||||
BIND(&if_code_is_off_heap);
|
||||
{
|
||||
TNode<Int32T> builtin_index = UncheckedCast<Int32T>(
|
||||
LoadObjectField(code, Code::kBuiltinIndexOffset, MachineType::Int32()));
|
||||
TNode<IntPtrT> builtin_entry_offset_from_isolate_root =
|
||||
IntPtrAdd(IntPtrConstant(IsolateData::builtin_entry_table_offset()),
|
||||
ChangeInt32ToIntPtr(Word32Shl(
|
||||
builtin_index, Int32Constant(kSystemPointerSizeLog2))));
|
||||
|
||||
var_result = ReinterpretCast<RawPtrT>(
|
||||
Load(MachineType::Pointer(),
|
||||
ExternalConstant(ExternalReference::isolate_root(isolate())),
|
||||
builtin_entry_offset_from_isolate_root));
|
||||
Goto(&out);
|
||||
}
|
||||
|
||||
BIND(&out);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ES6 section 21.2 RegExp Objects
|
||||
|
||||
@ -336,8 +385,7 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
ToDirectStringAssembler to_direct(state(), string);
|
||||
|
||||
TVARIABLE(HeapObject, var_result);
|
||||
Label out(this), interpreted(this), atom(this),
|
||||
runtime(this, Label::kDeferred);
|
||||
Label out(this), atom(this), runtime(this, Label::kDeferred);
|
||||
|
||||
// External constants.
|
||||
TNode<ExternalReference> isolate_address =
|
||||
@ -406,12 +454,13 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
|
||||
to_direct.TryToDirect(&runtime);
|
||||
|
||||
// Load the irregexp code object and offsets into the subject string. Both
|
||||
// depend on whether the string is one- or two-byte.
|
||||
// Load the irregexp code or bytecode object and offsets into the subject
|
||||
// string. Both depend on whether the string is one- or two-byte.
|
||||
|
||||
TVARIABLE(RawPtrT, var_string_start);
|
||||
TVARIABLE(RawPtrT, var_string_end);
|
||||
TVARIABLE(Object, var_code);
|
||||
TVARIABLE(Object, var_bytecode);
|
||||
|
||||
{
|
||||
TNode<RawPtrT> direct_string_data = to_direct.PointerToData(&runtime);
|
||||
@ -427,6 +476,8 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
&var_string_start, &var_string_end);
|
||||
var_code =
|
||||
UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpLatin1CodeIndex);
|
||||
var_bytecode = UnsafeLoadFixedArrayElement(
|
||||
data, JSRegExp::kIrregexpLatin1BytecodeIndex);
|
||||
Goto(&next);
|
||||
}
|
||||
|
||||
@ -437,6 +488,8 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
&var_string_start, &var_string_end);
|
||||
var_code =
|
||||
UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpUC16CodeIndex);
|
||||
var_bytecode = UnsafeLoadFixedArrayElement(
|
||||
data, JSRegExp::kIrregexpUC16BytecodeIndex);
|
||||
Goto(&next);
|
||||
}
|
||||
|
||||
@ -458,14 +511,28 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
#endif
|
||||
|
||||
GotoIf(TaggedIsSmi(var_code.value()), &runtime);
|
||||
GotoIfNot(IsCode(CAST(var_code.value())), &interpreted);
|
||||
TNode<Code> code = CAST(var_code.value());
|
||||
|
||||
// Ensure that a RegExp stack is allocated when using compiled Irregexp.
|
||||
// Tier-up in runtime if ticks are non-zero and tier-up hasn't happened yet
|
||||
// and ensure that a RegExp stack is allocated when using compiled Irregexp.
|
||||
{
|
||||
Label next(this);
|
||||
GotoIfNot(TaggedIsSmi(var_bytecode.value()), &next);
|
||||
CSA_ASSERT(this, SmiEqual(CAST(var_bytecode.value()),
|
||||
SmiConstant(JSRegExp::kUninitializedValue)));
|
||||
|
||||
// Ensure RegExp stack is allocated.
|
||||
TNode<IntPtrT> stack_size = UncheckedCast<IntPtrT>(
|
||||
Load(MachineType::IntPtr(), regexp_stack_memory_size_address));
|
||||
GotoIf(IntPtrEqual(stack_size, IntPtrZero()), &runtime);
|
||||
|
||||
// Check if tier-up is requested.
|
||||
TNode<Smi> ticks = CAST(
|
||||
UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpTierUpTicksIndex));
|
||||
GotoIf(SmiToInt32(ticks), &runtime);
|
||||
|
||||
Goto(&next);
|
||||
BIND(&next);
|
||||
}
|
||||
|
||||
Label if_success(this), if_exception(this, Label::kDeferred);
|
||||
@ -489,11 +556,13 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
MachineType arg1_type = type_int32;
|
||||
TNode<Int32T> arg1 = TruncateIntPtrToInt32(int_last_index);
|
||||
|
||||
// Argument 2: Start of string data.
|
||||
// Argument 2: Start of string data. This argument is ignored in the
|
||||
// interpreter.
|
||||
MachineType arg2_type = type_ptr;
|
||||
TNode<RawPtrT> arg2 = var_string_start.value();
|
||||
|
||||
// Argument 3: End of string data.
|
||||
// Argument 3: End of string data. This argument is ignored in the
|
||||
// interpreter.
|
||||
MachineType arg3_type = type_ptr;
|
||||
TNode<RawPtrT> arg3 = var_string_end.value();
|
||||
|
||||
@ -501,13 +570,25 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
MachineType arg4_type = type_ptr;
|
||||
TNode<ExternalReference> arg4 = static_offsets_vector_address;
|
||||
|
||||
// Argument 5: Set the number of capture registers to zero to force global
|
||||
// regexps to behave as non-global. This does not affect non-global
|
||||
// regexps.
|
||||
MachineType arg5_type = type_int32;
|
||||
TNode<Int32T> arg5 = Int32Constant(0);
|
||||
// Argument 5: Number of capture registers.
|
||||
// Setting this to the number of registers required to store all captures
|
||||
// forces global regexps to behave as non-global.
|
||||
TNode<Smi> capture_count = CAST(UnsafeLoadFixedArrayElement(
|
||||
data, JSRegExp::kIrregexpCaptureCountIndex));
|
||||
// capture_count is the number of captures without the match itself.
|
||||
// Required registers = (capture_count + 1) * 2.
|
||||
STATIC_ASSERT(Internals::IsValidSmi((JSRegExp::kMaxCaptures + 1) << 1));
|
||||
TNode<Smi> register_count =
|
||||
SmiShl(SmiAdd(capture_count, SmiConstant(1)), 1);
|
||||
|
||||
// Argument 6: Start (high end) of backtracking stack memory area.
|
||||
MachineType arg5_type = type_int32;
|
||||
TNode<Int32T> arg5 = SmiToInt32(register_count);
|
||||
|
||||
// Argument 6: Start (high end) of backtracking stack memory area. This
|
||||
// argument is ignored in the interpreter.
|
||||
// TODO(pthier): We should consider creating a dedicated external reference
|
||||
// for top of regexp stack instead of calculating it here for every
|
||||
// execution.
|
||||
TNode<RawPtrT> stack_start = UncheckedCast<RawPtrT>(
|
||||
Load(MachineType::Pointer(), regexp_stack_memory_address_address));
|
||||
TNode<IntPtrT> stack_size = UncheckedCast<IntPtrT>(
|
||||
@ -520,22 +601,26 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
|
||||
// Argument 7: Indicate that this is a direct call from JavaScript.
|
||||
MachineType arg7_type = type_int32;
|
||||
TNode<Int32T> arg7 = Int32Constant(1);
|
||||
TNode<Int32T> arg7 = Int32Constant(RegExp::CallOrigin::kFromJs);
|
||||
|
||||
// Argument 8: Pass current isolate address.
|
||||
MachineType arg8_type = type_ptr;
|
||||
TNode<ExternalReference> arg8 = isolate_address;
|
||||
|
||||
TNode<RawPtrT> code_entry = ReinterpretCast<RawPtrT>(
|
||||
IntPtrAdd(BitcastTaggedToWord(code),
|
||||
IntPtrConstant(Code::kHeaderSize - kHeapObjectTag)));
|
||||
// Argument 9: Regular expression object. This argument is ignored in native
|
||||
// irregexp code.
|
||||
MachineType arg9_type = type_tagged;
|
||||
TNode<JSRegExp> arg9 = regexp;
|
||||
|
||||
TNode<RawPtrT> code_entry = LoadCodeObjectEntry(code);
|
||||
|
||||
TNode<Int32T> result = UncheckedCast<Int32T>(CallCFunction(
|
||||
code_entry, retval_type, std::make_pair(arg0_type, arg0),
|
||||
std::make_pair(arg1_type, arg1), std::make_pair(arg2_type, arg2),
|
||||
std::make_pair(arg3_type, arg3), std::make_pair(arg4_type, arg4),
|
||||
std::make_pair(arg5_type, arg5), std::make_pair(arg6_type, arg6),
|
||||
std::make_pair(arg7_type, arg7), std::make_pair(arg8_type, arg8)));
|
||||
std::make_pair(arg7_type, arg7), std::make_pair(arg8_type, arg8),
|
||||
std::make_pair(arg9_type, arg9)));
|
||||
|
||||
// Check the result.
|
||||
// We expect exactly one result since we force the called regexp to behave
|
||||
@ -556,78 +641,6 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
Goto(&runtime);
|
||||
}
|
||||
|
||||
BIND(&interpreted);
|
||||
{
|
||||
// Tier-up in runtime to compiler if ticks are non-zero.
|
||||
TNode<Smi> ticks = CAST(
|
||||
UnsafeLoadFixedArrayElement(data, JSRegExp::kIrregexpTierUpTicksIndex));
|
||||
GotoIf(SmiToInt32(ticks), &runtime);
|
||||
|
||||
IncrementCounter(isolate()->counters()->regexp_entry_native(), 1);
|
||||
|
||||
// Set up args for the final call into IrregexpInterpreter.
|
||||
|
||||
MachineType type_int32 = MachineType::Int32();
|
||||
MachineType type_tagged = MachineType::AnyTagged();
|
||||
MachineType type_ptr = MachineType::Pointer();
|
||||
|
||||
// Result: A IrregexpInterpreter::Result return code.
|
||||
MachineType retval_type = type_int32;
|
||||
|
||||
// Argument 0: Pass current isolate address.
|
||||
MachineType arg0_type = type_ptr;
|
||||
TNode<ExternalReference> arg0 = isolate_address;
|
||||
|
||||
// Argument 1: Regular expression object.
|
||||
MachineType arg1_type = type_tagged;
|
||||
TNode<JSRegExp> arg1 = regexp;
|
||||
|
||||
// Argument 2: Original subject string.
|
||||
MachineType arg2_type = type_tagged;
|
||||
TNode<String> arg2 = string;
|
||||
|
||||
// Argument 3: Static offsets vector buffer.
|
||||
MachineType arg3_type = type_ptr;
|
||||
TNode<ExternalReference> arg3 = static_offsets_vector_address;
|
||||
|
||||
// Argument 4: Length of static offsets vector buffer.
|
||||
TNode<Smi> capture_count = CAST(UnsafeLoadFixedArrayElement(
|
||||
data, JSRegExp::kIrregexpCaptureCountIndex));
|
||||
TNode<Smi> register_count =
|
||||
SmiShl(SmiAdd(capture_count, SmiConstant(1)), 1);
|
||||
|
||||
MachineType arg4_type = type_int32;
|
||||
TNode<Int32T> arg4 = SmiToInt32(register_count);
|
||||
|
||||
// Argument 5: Previous index.
|
||||
MachineType arg5_type = type_int32;
|
||||
TNode<Int32T> arg5 = TruncateIntPtrToInt32(int_last_index);
|
||||
|
||||
TNode<ExternalReference> code_entry = ExternalConstant(
|
||||
ExternalReference::re_match_for_call_from_js(isolate()));
|
||||
|
||||
TNode<Int32T> result = UncheckedCast<Int32T>(CallCFunction(
|
||||
code_entry, retval_type, std::make_pair(arg0_type, arg0),
|
||||
std::make_pair(arg1_type, arg1), std::make_pair(arg2_type, arg2),
|
||||
std::make_pair(arg3_type, arg3), std::make_pair(arg4_type, arg4),
|
||||
std::make_pair(arg5_type, arg5)));
|
||||
|
||||
TNode<IntPtrT> int_result = ChangeInt32ToIntPtr(result);
|
||||
GotoIf(
|
||||
IntPtrEqual(int_result, IntPtrConstant(RegExp::kInternalRegExpSuccess)),
|
||||
&if_success);
|
||||
GotoIf(
|
||||
IntPtrEqual(int_result, IntPtrConstant(RegExp::kInternalRegExpFailure)),
|
||||
&if_failure);
|
||||
GotoIf(IntPtrEqual(int_result,
|
||||
IntPtrConstant(RegExp::kInternalRegExpException)),
|
||||
&if_exception);
|
||||
|
||||
CSA_ASSERT(this, IntPtrEqual(int_result,
|
||||
IntPtrConstant(RegExp::kInternalRegExpRetry)));
|
||||
Goto(&runtime);
|
||||
}
|
||||
|
||||
BIND(&if_success);
|
||||
{
|
||||
// Check that the last match info has space for the capture registers and
|
||||
@ -1812,7 +1825,6 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(TNode<Context> context,
|
||||
TNode<RegExpMatchInfo> match_indices =
|
||||
RegExpPrototypeExecBodyWithoutResult(context, CAST(regexp), string,
|
||||
&if_didnotmatch, true);
|
||||
|
||||
Label dosubstring(this), donotsubstring(this);
|
||||
Branch(var_atom.value(), &donotsubstring, &dosubstring);
|
||||
|
||||
|
@ -30,6 +30,8 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<Smi> SmiZero();
|
||||
TNode<IntPtrT> IntPtrZero();
|
||||
|
||||
TNode<RawPtrT> LoadCodeObjectEntry(TNode<Code> code);
|
||||
|
||||
// Allocate a RegExpResult with the given length (the number of captures,
|
||||
// including the match itself), index (the index where the match starts),
|
||||
// and input string.
|
||||
|
@ -217,6 +217,13 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
|
||||
Jump(static_cast<intptr_t>(code.address()), rmode, cond);
|
||||
}
|
||||
|
||||
void TurboAssembler::Jump(const ExternalReference& reference) {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
Move(scratch, reference);
|
||||
Jump(scratch);
|
||||
}
|
||||
|
||||
void TurboAssembler::Call(Register target, Condition cond) {
|
||||
// Block constant pool for the call instruction sequence.
|
||||
BlockConstPoolScope block_const_pool(this);
|
||||
|
@ -409,6 +409,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
void Jump(Register target, Condition cond = al);
|
||||
void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
|
||||
void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
|
||||
void Jump(const ExternalReference& reference) override;
|
||||
|
||||
// Perform a floating-point min or max operation with the
|
||||
// (IEEE-754-compatible) semantics of ARM64's fmin/fmax. Some cases, typically
|
||||
|
@ -1867,6 +1867,13 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Jump(const ExternalReference& reference) {
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.AcquireX();
|
||||
Mov(scratch, reference);
|
||||
Jump(scratch);
|
||||
}
|
||||
|
||||
void TurboAssembler::Call(Register target) {
|
||||
BlockPoolsScope scope(this);
|
||||
Blr(target);
|
||||
|
@ -889,6 +889,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
void Jump(Register target, Condition cond = al);
|
||||
void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
|
||||
void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
|
||||
void Jump(const ExternalReference& reference) override;
|
||||
|
||||
void Call(Register target);
|
||||
void Call(Address target, RelocInfo::Mode rmode);
|
||||
|
@ -1957,6 +1957,12 @@ void TurboAssembler::JumpCodeObject(Register code_object) {
|
||||
jmp(code_object);
|
||||
}
|
||||
|
||||
void TurboAssembler::Jump(const ExternalReference& reference) {
|
||||
DCHECK(root_array_available());
|
||||
jmp(Operand(kRootRegister, RootRegisterOffsetForExternalReferenceTableEntry(
|
||||
isolate(), reference)));
|
||||
}
|
||||
|
||||
void TurboAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
|
||||
DCHECK_IMPLIES(options().isolate_independent_code,
|
||||
Builtins::IsIsolateIndependentBuiltin(*code_object));
|
||||
|
@ -96,6 +96,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
void LoadCodeObjectEntry(Register destination, Register code_object) override;
|
||||
void CallCodeObject(Register code_object) override;
|
||||
void JumpCodeObject(Register code_object) override;
|
||||
void Jump(const ExternalReference& reference) override;
|
||||
|
||||
void RetpolineCall(Register reg);
|
||||
void RetpolineCall(Address destination, RelocInfo::Mode rmode);
|
||||
|
@ -50,6 +50,8 @@ class V8_EXPORT_PRIVATE TurboAssemblerBase : public Assembler {
|
||||
void set_has_frame(bool v) { has_frame_ = v; }
|
||||
bool has_frame() const { return has_frame_; }
|
||||
|
||||
virtual void Jump(const ExternalReference& reference) = 0;
|
||||
|
||||
// Calls the builtin given by the Smi in |builtin|. If builtins are embedded,
|
||||
// the trampoline Code object on the heap is not used.
|
||||
virtual void CallBuiltinByIndex(Register builtin_index) = 0;
|
||||
|
@ -1524,9 +1524,10 @@ void MacroAssembler::Pop(Operand dst) { popq(dst); }
|
||||
|
||||
void MacroAssembler::PopQuad(Operand dst) { popq(dst); }
|
||||
|
||||
void TurboAssembler::Jump(ExternalReference ext) {
|
||||
LoadAddress(kScratchRegister, ext);
|
||||
jmp(kScratchRegister);
|
||||
void TurboAssembler::Jump(const ExternalReference& reference) {
|
||||
DCHECK(root_array_available());
|
||||
jmp(Operand(kRootRegister, RootRegisterOffsetForExternalReferenceTableEntry(
|
||||
isolate(), reference)));
|
||||
}
|
||||
|
||||
void TurboAssembler::Jump(Operand op) { jmp(op); }
|
||||
|
@ -354,7 +354,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
void RetpolineCall(Address destination, RelocInfo::Mode rmode);
|
||||
|
||||
void Jump(Address destination, RelocInfo::Mode rmode);
|
||||
void Jump(ExternalReference ext);
|
||||
void Jump(const ExternalReference& reference) override;
|
||||
void Jump(Operand op);
|
||||
void Jump(Handle<Code> code_object, RelocInfo::Mode rmode,
|
||||
Condition cc = always);
|
||||
|
@ -1448,22 +1448,34 @@ void JSRegExp::JSRegExpVerify(Isolate* isolate) {
|
||||
break;
|
||||
}
|
||||
case JSRegExp::IRREGEXP: {
|
||||
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);
|
||||
// Smi : Not compiled yet (-1).
|
||||
// Code/ByteArray: Compiled code.
|
||||
// Code: Compiled irregexp code or trampoline to the interpreter.
|
||||
CHECK((one_byte_data.IsSmi() &&
|
||||
Smi::ToInt(one_byte_data) == JSRegExp::kUninitializedValue) ||
|
||||
(can_be_interpreted && one_byte_data.IsByteArray()) ||
|
||||
(can_be_native && one_byte_data.IsCode()));
|
||||
one_byte_data.IsCode());
|
||||
Object uc16_data = arr.get(JSRegExp::kIrregexpUC16CodeIndex);
|
||||
CHECK((uc16_data.IsSmi() &&
|
||||
Smi::ToInt(uc16_data) == JSRegExp::kUninitializedValue) ||
|
||||
(can_be_interpreted && uc16_data.IsByteArray()) ||
|
||||
(can_be_native && uc16_data.IsCode()));
|
||||
uc16_data.IsCode());
|
||||
|
||||
Object one_byte_bytecode =
|
||||
arr.get(JSRegExp::kIrregexpLatin1BytecodeIndex);
|
||||
// Smi : Not compiled yet (-1).
|
||||
// ByteArray: Bytecode to interpret regexp.
|
||||
CHECK((one_byte_bytecode.IsSmi() &&
|
||||
Smi::ToInt(one_byte_bytecode) == JSRegExp::kUninitializedValue) ||
|
||||
(can_be_interpreted && one_byte_bytecode.IsByteArray()));
|
||||
Object uc16_bytecode = arr.get(JSRegExp::kIrregexpUC16BytecodeIndex);
|
||||
CHECK((uc16_bytecode.IsSmi() &&
|
||||
Smi::ToInt(uc16_bytecode) == JSRegExp::kUninitializedValue) ||
|
||||
(can_be_interpreted && uc16_bytecode.IsByteArray()));
|
||||
|
||||
CHECK_IMPLIES(one_byte_data.IsSmi(), one_byte_bytecode.IsSmi());
|
||||
CHECK_IMPLIES(uc16_data.IsSmi(), uc16_bytecode.IsSmi());
|
||||
|
||||
CHECK(arr.get(JSRegExp::kIrregexpCaptureCountIndex).IsSmi());
|
||||
CHECK(arr.get(JSRegExp::kIrregexpMaxRegisterCountIndex).IsSmi());
|
||||
|
@ -3899,6 +3899,8 @@ void Factory::SetRegExpIrregexpData(Handle<JSRegExp> regexp,
|
||||
store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags));
|
||||
store->set(JSRegExp::kIrregexpLatin1CodeIndex, uninitialized);
|
||||
store->set(JSRegExp::kIrregexpUC16CodeIndex, uninitialized);
|
||||
store->set(JSRegExp::kIrregexpLatin1BytecodeIndex, uninitialized);
|
||||
store->set(JSRegExp::kIrregexpUC16BytecodeIndex, uninitialized);
|
||||
store->set(JSRegExp::kIrregexpMaxRegisterCountIndex, Smi::kZero);
|
||||
store->set(JSRegExp::kIrregexpCaptureCountIndex, Smi::FromInt(capture_count));
|
||||
store->set(JSRegExp::kIrregexpCaptureNameMapIndex, uninitialized);
|
||||
|
@ -80,23 +80,28 @@ void JSRegExp::SetDataAt(int index, Object value) {
|
||||
|
||||
bool JSRegExp::HasCompiledCode() const {
|
||||
if (TypeTag() != IRREGEXP) return false;
|
||||
Smi uninitialized = Smi::FromInt(kUninitializedValue);
|
||||
#ifdef DEBUG
|
||||
DCHECK(DataAt(kIrregexpLatin1CodeIndex).IsCode() ||
|
||||
DataAt(kIrregexpLatin1CodeIndex).IsByteArray() ||
|
||||
DataAt(kIrregexpLatin1CodeIndex) == Smi::FromInt(kUninitializedValue));
|
||||
DataAt(kIrregexpLatin1CodeIndex) == uninitialized);
|
||||
DCHECK(DataAt(kIrregexpUC16CodeIndex).IsCode() ||
|
||||
DataAt(kIrregexpUC16CodeIndex).IsByteArray() ||
|
||||
DataAt(kIrregexpUC16CodeIndex) == Smi::FromInt(kUninitializedValue));
|
||||
DataAt(kIrregexpUC16CodeIndex) == uninitialized);
|
||||
DCHECK(DataAt(kIrregexpLatin1BytecodeIndex).IsByteArray() ||
|
||||
DataAt(kIrregexpLatin1BytecodeIndex) == uninitialized);
|
||||
DCHECK(DataAt(kIrregexpUC16BytecodeIndex).IsByteArray() ||
|
||||
DataAt(kIrregexpUC16BytecodeIndex) == uninitialized);
|
||||
#endif // DEBUG
|
||||
Smi uninitialized = Smi::FromInt(kUninitializedValue);
|
||||
return (DataAt(kIrregexpLatin1CodeIndex) != uninitialized ||
|
||||
DataAt(kIrregexpUC16CodeIndex) != uninitialized);
|
||||
}
|
||||
|
||||
void JSRegExp::DiscardCompiledCodeForSerialization() {
|
||||
DCHECK(HasCompiledCode());
|
||||
SetDataAt(kIrregexpLatin1CodeIndex, Smi::FromInt(kUninitializedValue));
|
||||
SetDataAt(kIrregexpUC16CodeIndex, Smi::FromInt(kUninitializedValue));
|
||||
Smi uninitialized = Smi::FromInt(kUninitializedValue);
|
||||
SetDataAt(kIrregexpLatin1CodeIndex, uninitialized);
|
||||
SetDataAt(kIrregexpUC16CodeIndex, uninitialized);
|
||||
SetDataAt(kIrregexpLatin1BytecodeIndex, uninitialized);
|
||||
SetDataAt(kIrregexpUC16BytecodeIndex, uninitialized);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -103,6 +103,10 @@ class JSRegExp : public JSObject {
|
||||
void MarkTierUpForNextExec();
|
||||
|
||||
inline Type TypeTag() const;
|
||||
|
||||
// Maximum number of captures allowed.
|
||||
static constexpr int kMaxCaptures = 1 << 16;
|
||||
|
||||
// Number of captures (without the match itself).
|
||||
inline int CaptureCount();
|
||||
inline Flags GetFlags();
|
||||
@ -112,16 +116,19 @@ class JSRegExp : public JSObject {
|
||||
// Set implementation data after the object has been prepared.
|
||||
inline void SetDataAt(int index, Object value);
|
||||
|
||||
static int code_index(bool is_latin1) {
|
||||
if (is_latin1) {
|
||||
return kIrregexpLatin1CodeIndex;
|
||||
} else {
|
||||
return kIrregexpUC16CodeIndex;
|
||||
}
|
||||
static constexpr int code_index(bool is_latin1) {
|
||||
return is_latin1 ? kIrregexpLatin1CodeIndex : kIrregexpUC16CodeIndex;
|
||||
}
|
||||
|
||||
// This could be a Smi kUninitializedValue, a ByteArray, or Code.
|
||||
static constexpr int bytecode_index(bool is_latin1) {
|
||||
return is_latin1 ? kIrregexpLatin1BytecodeIndex
|
||||
: kIrregexpUC16BytecodeIndex;
|
||||
}
|
||||
|
||||
// This could be a Smi kUninitializedValue or Code.
|
||||
Object Code(bool is_latin1) const;
|
||||
// This could be a Smi kUninitializedValue or ByteArray.
|
||||
Object Bytecode(bool is_latin1) const;
|
||||
bool ShouldProduceBytecode();
|
||||
inline bool HasCompiledCode() const;
|
||||
inline void DiscardCompiledCodeForSerialization();
|
||||
@ -151,23 +158,33 @@ class JSRegExp : public JSObject {
|
||||
|
||||
static const int kAtomDataSize = kAtomPatternIndex + 1;
|
||||
|
||||
// Irregexp compiled code or bytecode for Latin1. If compilation
|
||||
// fails, this fields hold an exception object that should be
|
||||
// Irregexp compiled code or trampoline to interpreter for Latin1. If
|
||||
// compilation fails, this fields hold an exception object that should be
|
||||
// thrown if the regexp is used again.
|
||||
static const int kIrregexpLatin1CodeIndex = kDataIndex;
|
||||
// Irregexp compiled code or bytecode for UC16. If compilation
|
||||
// fails, this fields hold an exception object that should be
|
||||
// Irregexp compiled code or trampoline to interpreter for UC16. If
|
||||
// compilation fails, this fields hold an exception object that should be
|
||||
// thrown if the regexp is used again.
|
||||
static const int kIrregexpUC16CodeIndex = kDataIndex + 1;
|
||||
// Bytecode to interpret the regexp for Latin1. Contains kUninitializedValue
|
||||
// if we haven't compiled the regexp yet, regexp are always compiled or if
|
||||
// tier-up has happened (i.e. when kIrregexpLatin1CodeIndex contains native
|
||||
// irregexp code).
|
||||
static const int kIrregexpLatin1BytecodeIndex = kDataIndex + 2;
|
||||
// Bytecode to interpret the regexp for UC16. Contains kUninitializedValue if
|
||||
// we haven't compiled the regxp yet, regexp are always compiled or if tier-up
|
||||
// has happened (i.e. when kIrregexpUC16CodeIndex contains native irregexp
|
||||
// code).
|
||||
static const int kIrregexpUC16BytecodeIndex = kDataIndex + 3;
|
||||
// Maximal number of registers used by either Latin1 or UC16.
|
||||
// Only used to check that there is enough stack space
|
||||
static const int kIrregexpMaxRegisterCountIndex = kDataIndex + 2;
|
||||
static const int kIrregexpMaxRegisterCountIndex = kDataIndex + 4;
|
||||
// Number of captures in the compiled regexp.
|
||||
static const int kIrregexpCaptureCountIndex = kDataIndex + 3;
|
||||
static const int kIrregexpCaptureCountIndex = kDataIndex + 5;
|
||||
// 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 kIrregexpCaptureNameMapIndex = kDataIndex + 6;
|
||||
static const int kIrregexpTierUpTicksIndex = kDataIndex + 7;
|
||||
|
||||
static const int kIrregexpDataSize = kIrregexpTierUpTicksIndex + 1;
|
||||
|
||||
|
@ -6141,6 +6141,10 @@ Object JSRegExp::Code(bool is_latin1) const {
|
||||
return DataAt(code_index(is_latin1));
|
||||
}
|
||||
|
||||
Object JSRegExp::Bytecode(bool is_latin1) const {
|
||||
return DataAt(bytecode_index(is_latin1));
|
||||
}
|
||||
|
||||
bool JSRegExp::ShouldProduceBytecode() {
|
||||
return FLAG_regexp_interpret_all ||
|
||||
(FLAG_regexp_tier_up && !MarkedForTierUp());
|
||||
|
@ -40,6 +40,9 @@ namespace internal {
|
||||
* Each call to a public method should retain this convention.
|
||||
*
|
||||
* The stack will have the following structure:
|
||||
* - fp[56] Address regexp (address of the JSRegExp object; unused in
|
||||
* native code, passed to match signature of
|
||||
* the interpreter)
|
||||
* - fp[52] Isolate* isolate (address of the current isolate)
|
||||
* - fp[48] direct_call (if 1, direct call from JavaScript code,
|
||||
* if 0, call through the runtime system).
|
||||
@ -83,7 +86,8 @@ namespace internal {
|
||||
* int num_capture_registers,
|
||||
* byte* stack_area_base,
|
||||
* bool direct_call = false,
|
||||
* Isolate* isolate);
|
||||
* Isolate* isolate,
|
||||
* Address regexp);
|
||||
* The call is performed by NativeRegExpMacroAssembler::Execute()
|
||||
* (in regexp-macro-assembler.cc) via the GeneratedCode wrapper.
|
||||
*/
|
||||
|
@ -55,7 +55,10 @@ namespace internal {
|
||||
* (as referred to in
|
||||
* the code)
|
||||
*
|
||||
* - fp[96] isolate Address of the current isolate.
|
||||
* - fp[104] Address regexp Address of the JSRegExp object. Unused in
|
||||
* native code, passed to match signature of
|
||||
* the interpreter.
|
||||
* - fp[96] isolate Address of the current isolate.
|
||||
* ^^^ sp when called ^^^
|
||||
* - fp[88] lr Return from the RegExp code.
|
||||
* - fp[80] r29 Old frame pointer (CalleeSaved).
|
||||
@ -93,7 +96,8 @@ namespace internal {
|
||||
* int num_capture_registers,
|
||||
* byte* stack_area_base,
|
||||
* bool direct_call = false,
|
||||
* Isolate* isolate);
|
||||
* Isolate* isolate,
|
||||
* Address regexp);
|
||||
* The call is performed by NativeRegExpMacroAssembler::Execute()
|
||||
* (in regexp-macro-assembler.cc) via the GeneratedCode wrapper.
|
||||
*/
|
||||
|
@ -34,6 +34,9 @@ namespace internal {
|
||||
*
|
||||
* Each call to a public method should retain this convention.
|
||||
* The stack will have the following structure:
|
||||
* - Address regexp (address of the JSRegExp object; unused in
|
||||
* native code, passed to match signature of
|
||||
* the interpreter)
|
||||
* - Isolate* isolate (address of the current isolate)
|
||||
* - direct_call (if 1, direct call from JavaScript code, if 0
|
||||
* call through the runtime system)
|
||||
@ -73,7 +76,8 @@ namespace internal {
|
||||
* int num_capture_registers,
|
||||
* byte* stack_area_base,
|
||||
* bool direct_call = false,
|
||||
* Isolate* isolate);
|
||||
* Isolate* isolate
|
||||
* Address regexp);
|
||||
*/
|
||||
|
||||
#define __ ACCESS_MASM(masm_)
|
||||
|
@ -516,6 +516,7 @@ class RegExpCompiler {
|
||||
|
||||
const char* const error_message = nullptr;
|
||||
Object code;
|
||||
Object bytecode;
|
||||
int num_registers = 0;
|
||||
};
|
||||
|
||||
|
@ -811,7 +811,7 @@ IrregexpInterpreter::Result IrregexpInterpreter::Match(
|
||||
}
|
||||
|
||||
bool is_one_byte = String::IsOneByteRepresentationUnderneath(subject_string);
|
||||
ByteArray code_array = ByteArray::cast(regexp.Code(is_one_byte));
|
||||
ByteArray code_array = ByteArray::cast(regexp.Bytecode(is_one_byte));
|
||||
|
||||
return MatchInternal(isolate, code_array, subject_string, registers,
|
||||
registers_length, start_position, call_origin);
|
||||
@ -856,10 +856,12 @@ IrregexpInterpreter::Result IrregexpInterpreter::MatchInternal(
|
||||
// This method is called through an external reference from RegExpExecInternal
|
||||
// builtin.
|
||||
IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromJs(
|
||||
Isolate* isolate, Address regexp, Address subject, int* registers,
|
||||
int32_t registers_length, int32_t start_position) {
|
||||
Address subject, int32_t start_position, Address, Address, int* registers,
|
||||
int32_t registers_length, Address, RegExp::CallOrigin call_origin,
|
||||
Isolate* isolate, Address regexp) {
|
||||
DCHECK_NOT_NULL(isolate);
|
||||
DCHECK_NOT_NULL(registers);
|
||||
DCHECK(call_origin == RegExp::CallOrigin::kFromJs);
|
||||
|
||||
DisallowHeapAllocation no_gc;
|
||||
DisallowJavascriptExecution no_js(isolate);
|
||||
@ -868,7 +870,7 @@ IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromJs(
|
||||
JSRegExp regexp_obj = JSRegExp::cast(Object(regexp));
|
||||
|
||||
return Match(isolate, regexp_obj, subject_string, registers, registers_length,
|
||||
start_position, RegExp::CallOrigin::kFromJs);
|
||||
start_position, call_origin);
|
||||
}
|
||||
|
||||
IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromRuntime(
|
||||
|
@ -31,10 +31,15 @@ class V8_EXPORT_PRIVATE IrregexpInterpreter : public AllStatic {
|
||||
|
||||
// In case a StackOverflow occurs, EXCEPTION is returned. The caller is
|
||||
// responsible for creating the exception.
|
||||
static Result MatchForCallFromJs(Isolate* isolate, Address regexp,
|
||||
Address subject, int* registers,
|
||||
int32_t registers_length,
|
||||
int32_t start_position);
|
||||
// Arguments input_start, input_end and backtrack_stack are
|
||||
// unused. They are only passed to match the signature of the native irregex
|
||||
// code.
|
||||
static Result MatchForCallFromJs(Address subject, int32_t start_position,
|
||||
Address input_start, Address input_end,
|
||||
int* registers, int32_t registers_length,
|
||||
Address backtrack_stack,
|
||||
RegExp::CallOrigin call_origin,
|
||||
Isolate* isolate, Address regexp);
|
||||
|
||||
static Result MatchInternal(Isolate* isolate, ByteArray code_array,
|
||||
String subject_string, int* registers,
|
||||
|
@ -219,7 +219,7 @@ int NativeRegExpMacroAssembler::CheckStackGuardState(
|
||||
}
|
||||
|
||||
// Returns a {Result} sentinel, or the number of successful matches.
|
||||
int NativeRegExpMacroAssembler::Match(Handle<Code> regexp_code,
|
||||
int NativeRegExpMacroAssembler::Match(Handle<JSRegExp> regexp,
|
||||
Handle<String> subject,
|
||||
int* offsets_vector,
|
||||
int offsets_vector_length,
|
||||
@ -262,31 +262,36 @@ int NativeRegExpMacroAssembler::Match(Handle<Code> regexp_code,
|
||||
StringCharacterPosition(subject_ptr, start_offset + slice_offset, no_gc);
|
||||
int byte_length = char_length << char_size_shift;
|
||||
const byte* input_end = input_start + byte_length;
|
||||
return Execute(*regexp_code, *subject, start_offset, input_start, input_end,
|
||||
offsets_vector, offsets_vector_length, isolate);
|
||||
return Execute(*subject, start_offset, input_start, input_end, offsets_vector,
|
||||
offsets_vector_length, isolate, *regexp);
|
||||
}
|
||||
|
||||
// Returns a {Result} sentinel, or the number of successful matches.
|
||||
// TODO(pthier): The JSRegExp object is passed to native irregexp code to match
|
||||
// the signature of the interpreter. We should get rid of JS objects passed to
|
||||
// internal methods.
|
||||
int NativeRegExpMacroAssembler::Execute(
|
||||
Code code,
|
||||
String input, // This needs to be the unpacked (sliced, cons) string.
|
||||
int start_offset, const byte* input_start, const byte* input_end,
|
||||
int* output, int output_size, Isolate* isolate) {
|
||||
int* output, int output_size, Isolate* isolate, JSRegExp regexp) {
|
||||
// Ensure that the minimum stack has been allocated.
|
||||
RegExpStackScope stack_scope(isolate);
|
||||
Address stack_base = stack_scope.stack()->stack_base();
|
||||
|
||||
int direct_call = 0;
|
||||
bool is_one_byte = String::IsOneByteRepresentationUnderneath(input);
|
||||
Code code = Code::cast(regexp.Code(is_one_byte));
|
||||
RegExp::CallOrigin call_origin = RegExp::CallOrigin::kFromRuntime;
|
||||
|
||||
using RegexpMatcherSig = int(
|
||||
Address input_string, int start_offset, // NOLINT(readability/casting)
|
||||
const byte* input_start, const byte* input_end, int* output,
|
||||
int output_size, Address stack_base, int direct_call, Isolate* isolate);
|
||||
int output_size, Address stack_base, int call_origin, Isolate* isolate,
|
||||
Address regexp);
|
||||
|
||||
auto fn = GeneratedCode<RegexpMatcherSig>::FromCode(code);
|
||||
int result =
|
||||
fn.CallIrregexp(input.ptr(), start_offset, input_start, input_end, output,
|
||||
output_size, stack_base, direct_call, isolate);
|
||||
int result = fn.CallIrregexp(input.ptr(), start_offset, input_start,
|
||||
input_end, output, output_size, stack_base,
|
||||
call_origin, isolate, regexp.ptr());
|
||||
DCHECK(result >= RETRY);
|
||||
|
||||
if (result == EXCEPTION && !isolate->has_pending_exception()) {
|
||||
|
@ -223,7 +223,7 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
|
||||
bool CanReadUnaligned() override;
|
||||
|
||||
// Returns a {Result} sentinel, or the number of successful matches.
|
||||
static int Match(Handle<Code> regexp, Handle<String> subject,
|
||||
static int Match(Handle<JSRegExp> regexp, Handle<String> subject,
|
||||
int* offsets_vector, int offsets_vector_length,
|
||||
int previous_index, Isolate* isolate);
|
||||
|
||||
@ -254,11 +254,11 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
|
||||
}
|
||||
|
||||
// Returns a {Result} sentinel, or the number of successful matches.
|
||||
V8_EXPORT_PRIVATE static int Execute(Code code, String input,
|
||||
int start_offset,
|
||||
V8_EXPORT_PRIVATE static int Execute(String input, int start_offset,
|
||||
const byte* input_start,
|
||||
const byte* input_end, int* output,
|
||||
int output_size, Isolate* isolate);
|
||||
int output_size, Isolate* isolate,
|
||||
JSRegExp regexp);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -692,7 +692,7 @@ RegExpParser::RegExpParserState* RegExpParser::ParseOpenParenthesis(
|
||||
}
|
||||
}
|
||||
if (subexpr_type == CAPTURE) {
|
||||
if (captures_started_ >= kMaxCaptures) {
|
||||
if (captures_started_ >= JSRegExp::kMaxCaptures) {
|
||||
ReportError(CStrVector("Too many captures"));
|
||||
return nullptr;
|
||||
}
|
||||
@ -800,7 +800,7 @@ bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
|
||||
uc32 c = current();
|
||||
if (IsDecimalDigit(c)) {
|
||||
value = 10 * value + (c - '0');
|
||||
if (value > kMaxCaptures) {
|
||||
if (value > JSRegExp::kMaxCaptures) {
|
||||
Reset(start);
|
||||
return false;
|
||||
}
|
||||
|
@ -221,7 +221,6 @@ class V8_EXPORT_PRIVATE RegExpParser {
|
||||
|
||||
static bool IsSyntaxCharacterOrSlash(uc32 c);
|
||||
|
||||
static const int kMaxCaptures = 1 << 16;
|
||||
static const uc32 kEndMarker = (1 << 21);
|
||||
|
||||
private:
|
||||
|
@ -301,13 +301,14 @@ bool RegExpImpl::EnsureCompiledIrregexp(Isolate* isolate, Handle<JSRegExp> re,
|
||||
Handle<String> sample_subject,
|
||||
bool is_one_byte) {
|
||||
Object compiled_code = re->Code(is_one_byte);
|
||||
Object bytecode = re->Bytecode(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();
|
||||
re->MarkedForTierUp() && bytecode.IsByteArray();
|
||||
|
||||
if (FLAG_trace_regexp_tier_up && needs_tier_up_compilation) {
|
||||
PrintF("JSRegExp object %p needs tier-up compilation\n",
|
||||
@ -315,14 +316,12 @@ bool RegExpImpl::EnsureCompiledIrregexp(Isolate* isolate, Handle<JSRegExp> re,
|
||||
}
|
||||
|
||||
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());
|
||||
DCHECK(compiled_code.IsCode());
|
||||
DCHECK_IMPLIES(FLAG_regexp_interpret_all, bytecode.IsByteArray());
|
||||
return true;
|
||||
}
|
||||
|
||||
DCHECK_IMPLIES(needs_tier_up_compilation, compiled_code.IsByteArray());
|
||||
DCHECK_IMPLIES(needs_tier_up_compilation, bytecode.IsByteArray());
|
||||
|
||||
return CompileIrregexp(isolate, re, sample_subject, is_one_byte);
|
||||
}
|
||||
@ -332,20 +331,25 @@ namespace {
|
||||
|
||||
bool RegExpCodeIsValidForPreCompilation(Handle<JSRegExp> re, bool is_one_byte) {
|
||||
Object entry = re->Code(is_one_byte);
|
||||
Object bytecode = re->Bytecode(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
|
||||
// compiling the regexp before the tier-up, or it can contain a trampoline to
|
||||
// the regexp interpreter, in which case the bytecode field contains 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());
|
||||
DCHECK(bytecode.IsSmi());
|
||||
int entry_value = Smi::ToInt(entry);
|
||||
int bytecode_value = Smi::ToInt(bytecode);
|
||||
DCHECK_EQ(JSRegExp::kUninitializedValue, entry_value);
|
||||
DCHECK_EQ(JSRegExp::kUninitializedValue, bytecode_value);
|
||||
} else {
|
||||
DCHECK(entry.IsByteArray() || entry.IsSmi());
|
||||
DCHECK(entry.IsSmi() || (entry.IsCode() && bytecode.IsByteArray()));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -395,7 +399,22 @@ bool RegExpImpl::CompileIrregexp(Isolate* isolate, Handle<JSRegExp> re,
|
||||
|
||||
Handle<FixedArray> data =
|
||||
Handle<FixedArray>(FixedArray::cast(re->data()), isolate);
|
||||
data->set(JSRegExp::code_index(is_one_byte), compile_data.code);
|
||||
if (compile_data.compilation_target == RegExpCompilationTarget::kNative) {
|
||||
data->set(JSRegExp::code_index(is_one_byte), compile_data.code);
|
||||
// Reset bytecode to uninitialized. In case we use tier-up we know that
|
||||
// tier-up has happened this way.
|
||||
data->set(JSRegExp::bytecode_index(is_one_byte),
|
||||
Smi::FromInt(JSRegExp::kUninitializedValue));
|
||||
} else {
|
||||
DCHECK_EQ(compile_data.compilation_target,
|
||||
RegExpCompilationTarget::kBytecode);
|
||||
// Store code generated by compiler in bytecode and trampoline to
|
||||
// interpreter in code.
|
||||
data->set(JSRegExp::bytecode_index(is_one_byte), compile_data.code);
|
||||
Handle<Code> trampoline =
|
||||
BUILTIN_CODE(isolate, RegExpInterpreterTrampoline);
|
||||
data->set(JSRegExp::code_index(is_one_byte), *trampoline);
|
||||
}
|
||||
SetIrregexpCaptureNameMap(*data, compile_data.capture_name_map);
|
||||
int register_max = IrregexpMaxRegisterCount(*data);
|
||||
if (compile_data.register_count > register_max) {
|
||||
@ -440,7 +459,7 @@ int RegExpImpl::IrregexpNumberOfRegisters(FixedArray re) {
|
||||
}
|
||||
|
||||
ByteArray RegExpImpl::IrregexpByteCode(FixedArray re, bool is_one_byte) {
|
||||
return ByteArray::cast(re.get(JSRegExp::code_index(is_one_byte)));
|
||||
return ByteArray::cast(re.get(JSRegExp::bytecode_index(is_one_byte)));
|
||||
}
|
||||
|
||||
Code RegExpImpl::IrregexpNativeCode(FixedArray re, bool is_one_byte) {
|
||||
@ -498,12 +517,11 @@ int RegExpImpl::IrregexpExecRaw(Isolate* isolate, Handle<JSRegExp> regexp,
|
||||
DCHECK(output_size >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2);
|
||||
do {
|
||||
EnsureCompiledIrregexp(isolate, regexp, subject, is_one_byte);
|
||||
Handle<Code> code(IrregexpNativeCode(*irregexp, is_one_byte), isolate);
|
||||
// The stack is used to allocate registers for the compiled regexp code.
|
||||
// This means that in case of failure, the output registers array is left
|
||||
// untouched and contains the capture results from the previous successful
|
||||
// match. We can use that to set the last match info lazily.
|
||||
int res = NativeRegExpMacroAssembler::Match(code, subject, output,
|
||||
int res = NativeRegExpMacroAssembler::Match(regexp, subject, output,
|
||||
output_size, index, isolate);
|
||||
if (res != NativeRegExpMacroAssembler::RETRY) {
|
||||
DCHECK(res != NativeRegExpMacroAssembler::EXCEPTION ||
|
||||
@ -862,6 +880,7 @@ bool RegExpImpl::Compile(Isolate* isolate, Zone* zone, RegExpCompileData* data,
|
||||
data->error =
|
||||
isolate->factory()->NewStringFromAsciiChecked(result.error_message);
|
||||
}
|
||||
|
||||
data->code = result.code;
|
||||
data->register_count = result.num_registers;
|
||||
|
||||
|
@ -23,8 +23,8 @@ struct RegExpCompileData {
|
||||
// The compiled Node graph as produced by RegExpTree::ToNode methods.
|
||||
RegExpNode* node = nullptr;
|
||||
|
||||
// The generated code as produced by the compiler. Either a Code object (for
|
||||
// irregexp native code) or a ByteArray (for irregexp bytecode).
|
||||
// Either the generated code as produced by the compiler or a trampoline
|
||||
// to the interpreter.
|
||||
Object code;
|
||||
|
||||
// True, iff the pattern is a 'simple' atom with zero captures. In other
|
||||
|
@ -48,6 +48,8 @@ namespace internal {
|
||||
*
|
||||
* The stack will have the following content, in some order, indexable from the
|
||||
* frame pointer (see, e.g., kStackHighEnd):
|
||||
* - Address regexp (address of the JSRegExp object; unused in native
|
||||
* code, passed to match signature of interpreter)
|
||||
* - Isolate* isolate (address of the current isolate)
|
||||
* - direct_call (if 1, direct call from JavaScript code, if 0 call
|
||||
* through the runtime system)
|
||||
@ -75,9 +77,8 @@ namespace internal {
|
||||
* "character -1" in the string (i.e., char_size() bytes before the first
|
||||
* character of the string). The remaining registers starts out uninitialized.
|
||||
*
|
||||
* The first seven values must be provided by the calling code by
|
||||
* calling the code's entry address cast to a function pointer with the
|
||||
* following signature:
|
||||
* The argument values must be provided by the calling code by calling the
|
||||
* code's entry address cast to a function pointer with the following signature:
|
||||
* int (*match)(String input_string,
|
||||
* int start_index,
|
||||
* Address start,
|
||||
@ -86,7 +87,8 @@ namespace internal {
|
||||
* int num_capture_registers,
|
||||
* byte* stack_area_base,
|
||||
* bool direct_call = false,
|
||||
* Isolate* isolate);
|
||||
* Isolate* isolate,
|
||||
* Address regexp);
|
||||
*/
|
||||
|
||||
#define __ ACCESS_MASM((&masm_))
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "src/codegen/assembler-arch.h"
|
||||
#include "src/codegen/macro-assembler.h"
|
||||
#include "src/init/v8.h"
|
||||
#include "src/objects/js-regexp-inl.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/regexp/regexp-bytecode-generator.h"
|
||||
#include "src/regexp/regexp-compiler.h"
|
||||
@ -630,16 +631,35 @@ class ContextInitializer {
|
||||
v8::Local<v8::Context> env_;
|
||||
};
|
||||
|
||||
static ArchRegExpMacroAssembler::Result Execute(Code code, String input,
|
||||
// Create new JSRegExp object with only necessary fields (for this tests)
|
||||
// initialized.
|
||||
static Handle<JSRegExp> CreateJSRegExp(Handle<String> source, Handle<Code> code,
|
||||
bool is_unicode = false) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<JSFunction> constructor = isolate->regexp_function();
|
||||
Handle<JSRegExp> regexp =
|
||||
Handle<JSRegExp>::cast(factory->NewJSObject(constructor));
|
||||
|
||||
factory->SetRegExpIrregexpData(regexp, JSRegExp::IRREGEXP, source,
|
||||
JSRegExp::kNone, 0);
|
||||
regexp->SetDataAt(is_unicode ? JSRegExp::kIrregexpUC16CodeIndex
|
||||
: JSRegExp::kIrregexpLatin1CodeIndex,
|
||||
*code);
|
||||
|
||||
return regexp;
|
||||
}
|
||||
|
||||
static ArchRegExpMacroAssembler::Result Execute(JSRegExp regexp, String input,
|
||||
int start_offset,
|
||||
Address input_start,
|
||||
Address input_end,
|
||||
int* captures) {
|
||||
return static_cast<NativeRegExpMacroAssembler::Result>(
|
||||
NativeRegExpMacroAssembler::Execute(code, input, start_offset,
|
||||
reinterpret_cast<byte*>(input_start),
|
||||
reinterpret_cast<byte*>(input_end),
|
||||
captures, 0, CcTest::i_isolate()));
|
||||
NativeRegExpMacroAssembler::Execute(
|
||||
input, start_offset, reinterpret_cast<byte*>(input_start),
|
||||
reinterpret_cast<byte*>(input_end), captures, 0, CcTest::i_isolate(),
|
||||
regexp));
|
||||
}
|
||||
|
||||
TEST(MacroAssemblerNativeSuccess) {
|
||||
@ -657,19 +677,15 @@ TEST(MacroAssemblerNativeSuccess) {
|
||||
Handle<String> source = factory->NewStringFromStaticChars("");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
|
||||
|
||||
int captures[4] = {42, 37, 87, 117};
|
||||
Handle<String> input = factory->NewStringFromStaticChars("foofoo");
|
||||
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
NativeRegExpMacroAssembler::Result result =
|
||||
Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + seq_input->length(),
|
||||
captures);
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*regexp, *input, 0, start_adr, start_adr + seq_input->length(), captures);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
CHECK_EQ(-1, captures[0]);
|
||||
@ -711,19 +727,15 @@ TEST(MacroAssemblerNativeSimple) {
|
||||
Handle<String> source = factory->NewStringFromStaticChars("^foo");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
|
||||
|
||||
int captures[4] = {42, 37, 87, 117};
|
||||
Handle<String> input = factory->NewStringFromStaticChars("foofoo");
|
||||
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
NativeRegExpMacroAssembler::Result result =
|
||||
Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + input->length(),
|
||||
captures);
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length(), captures);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
CHECK_EQ(0, captures[0]);
|
||||
@ -735,11 +747,7 @@ TEST(MacroAssemblerNativeSimple) {
|
||||
seq_input = Handle<SeqOneByteString>::cast(input);
|
||||
start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
result = Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + input->length(),
|
||||
result = Execute(*regexp, *input, 0, start_adr, start_adr + input->length(),
|
||||
captures);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
|
||||
@ -778,6 +786,7 @@ TEST(MacroAssemblerNativeSimpleUC16) {
|
||||
Handle<String> source = factory->NewStringFromStaticChars("^foo");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code, true);
|
||||
|
||||
int captures[4] = {42, 37, 87, 117};
|
||||
const uc16 input_data[6] = {'f', 'o', 'o', 'f', 'o',
|
||||
@ -787,13 +796,8 @@ TEST(MacroAssemblerNativeSimpleUC16) {
|
||||
Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
NativeRegExpMacroAssembler::Result result =
|
||||
Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + input->length(),
|
||||
captures);
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length(), captures);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
CHECK_EQ(0, captures[0]);
|
||||
@ -808,12 +812,8 @@ TEST(MacroAssemblerNativeSimpleUC16) {
|
||||
seq_input = Handle<SeqTwoByteString>::cast(input);
|
||||
start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
result = Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + input->length() * 2,
|
||||
captures);
|
||||
result = Execute(*regexp, *input, 0, start_adr,
|
||||
start_adr + input->length() * 2, captures);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
|
||||
}
|
||||
@ -843,13 +843,14 @@ TEST(MacroAssemblerNativeBacktrack) {
|
||||
Handle<String> source = factory->NewStringFromStaticChars("..........");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
|
||||
|
||||
Handle<String> input = factory->NewStringFromStaticChars("foofoo");
|
||||
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*code, *input, 0, start_adr, start_adr + input->length(), nullptr);
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length(), nullptr);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
|
||||
}
|
||||
@ -883,19 +884,15 @@ TEST(MacroAssemblerNativeBackReferenceLATIN1) {
|
||||
Handle<String> source = factory->NewStringFromStaticChars("^(..)..\1");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
|
||||
|
||||
Handle<String> input = factory->NewStringFromStaticChars("fooofo");
|
||||
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
int output[4];
|
||||
NativeRegExpMacroAssembler::Result result =
|
||||
Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + input->length(),
|
||||
output);
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length(), output);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
CHECK_EQ(0, output[0]);
|
||||
@ -933,6 +930,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
|
||||
Handle<String> source = factory->NewStringFromStaticChars("^(..)..\1");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code, true);
|
||||
|
||||
const uc16 input_data[6] = {'f', 0x2028, 'o', 'o', 'f', 0x2028};
|
||||
Handle<String> input = factory->NewStringFromTwoByte(
|
||||
@ -941,13 +939,8 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
int output[4];
|
||||
NativeRegExpMacroAssembler::Result result =
|
||||
Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + input->length() * 2,
|
||||
output);
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length() * 2, output);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
CHECK_EQ(0, output[0]);
|
||||
@ -992,18 +985,19 @@ TEST(MacroAssemblernativeAtStart) {
|
||||
Handle<String> source = factory->NewStringFromStaticChars("(^f|ob)");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
|
||||
|
||||
Handle<String> input = factory->NewStringFromStaticChars("foobar");
|
||||
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*code, *input, 0, start_adr, start_adr + input->length(), nullptr);
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length(), nullptr);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
|
||||
result = Execute(*code, *input, 3, start_adr + 3, start_adr + input->length(),
|
||||
nullptr);
|
||||
result = Execute(*regexp, *input, 3, start_adr + 3,
|
||||
start_adr + input->length(), nullptr);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
}
|
||||
@ -1045,19 +1039,15 @@ TEST(MacroAssemblerNativeBackRefNoCase) {
|
||||
factory->NewStringFromStaticChars("^(abc)\1\1(?!\1)...(?!\1)");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
|
||||
|
||||
Handle<String> input = factory->NewStringFromStaticChars("aBcAbCABCxYzab");
|
||||
Handle<SeqOneByteString> seq_input = Handle<SeqOneByteString>::cast(input);
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
int output[4];
|
||||
NativeRegExpMacroAssembler::Result result =
|
||||
Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + input->length(),
|
||||
output);
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length(), output);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
CHECK_EQ(0, output[0]);
|
||||
@ -1145,6 +1135,7 @@ TEST(MacroAssemblerNativeRegisters) {
|
||||
Handle<String> source = factory->NewStringFromStaticChars("<loop test>");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
|
||||
|
||||
// String long enough for test (content doesn't matter).
|
||||
Handle<String> input = factory->NewStringFromStaticChars("foofoofoofoofoo");
|
||||
@ -1152,13 +1143,8 @@ TEST(MacroAssemblerNativeRegisters) {
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
int output[6];
|
||||
NativeRegExpMacroAssembler::Result result =
|
||||
Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + input->length(),
|
||||
output);
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length(), output);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
CHECK_EQ(0, output[0]);
|
||||
@ -1189,6 +1175,7 @@ TEST(MacroAssemblerStackOverflow) {
|
||||
factory->NewStringFromStaticChars("<stack overflow test>");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
|
||||
|
||||
// String long enough for test (content doesn't matter).
|
||||
Handle<String> input = factory->NewStringFromStaticChars("dummy");
|
||||
@ -1196,7 +1183,7 @@ TEST(MacroAssemblerStackOverflow) {
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*code, *input, 0, start_adr, start_adr + input->length(), nullptr);
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length(), nullptr);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::EXCEPTION, result);
|
||||
CHECK(isolate->has_pending_exception());
|
||||
@ -1231,6 +1218,7 @@ TEST(MacroAssemblerNativeLotsOfRegisters) {
|
||||
factory->NewStringFromStaticChars("<huge register space test>");
|
||||
Handle<Object> code_object = m.GetCode(source);
|
||||
Handle<Code> code = Handle<Code>::cast(code_object);
|
||||
Handle<JSRegExp> regexp = CreateJSRegExp(source, code);
|
||||
|
||||
// String long enough for test (content doesn't matter).
|
||||
Handle<String> input = factory->NewStringFromStaticChars("sample text");
|
||||
@ -1238,13 +1226,8 @@ TEST(MacroAssemblerNativeLotsOfRegisters) {
|
||||
Address start_adr = seq_input->GetCharsAddress();
|
||||
|
||||
int captures[2];
|
||||
NativeRegExpMacroAssembler::Result result =
|
||||
Execute(*code,
|
||||
*input,
|
||||
0,
|
||||
start_adr,
|
||||
start_adr + input->length(),
|
||||
captures);
|
||||
NativeRegExpMacroAssembler::Result result = Execute(
|
||||
*regexp, *input, 0, start_adr, start_adr + input->length(), captures);
|
||||
|
||||
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
|
||||
CHECK_EQ(0, captures[0]);
|
||||
|
Loading…
Reference in New Issue
Block a user