зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1594545: Part 3: Labels and backtracking r=jandem
This patch implements labels and backtracking. Pushing the address of a label onto the backtrack stack is somewhat tricky, because PushBacktrack is generally called before Bind. This patch adds code to store the CodeOffset that must be patched alongside the Label. (This works, because we only ever push a given label on the backtrack stack in a single place.) The actual machinery of patching will be added in a later patch. As part of backtracking, we also implement backtrack stack limit checks. The OOL helper that is called if those checks fail will be added in a later patch. Depends on D68414 Differential Revision: https://phabricator.services.mozilla.com/D68415 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
1850525f8f
Коммит
209796c6c3
|
@ -38,6 +38,11 @@ class SMRegExpMacroAssembler final : public NativeRegExpMacroAssembler {
|
|||
virtual void PopCurrentPosition();
|
||||
virtual void PushCurrentPosition();
|
||||
|
||||
virtual void Backtrack();
|
||||
virtual void Bind(Label* label);
|
||||
virtual void GoTo(Label* label);
|
||||
virtual void PushBacktrack(Label* label);
|
||||
|
||||
|
||||
private:
|
||||
// Push a register on the backtrack stack.
|
||||
|
@ -46,6 +51,18 @@ class SMRegExpMacroAssembler final : public NativeRegExpMacroAssembler {
|
|||
// Pop a value from the backtrack stack.
|
||||
void Pop(js::jit::Register target);
|
||||
|
||||
void JumpOrBacktrack(Label* to);
|
||||
|
||||
// MacroAssembler methods that take a Label can be called with a
|
||||
// null label, which means that we should backtrack if we would jump
|
||||
// to that label. This is a helper to avoid writing out the same
|
||||
// logic a dozen times.
|
||||
inline js::jit::Label* LabelOrBacktrack(Label* to) {
|
||||
return to ? to->inner() : &backtrack_label_;
|
||||
}
|
||||
|
||||
void CheckBacktrackStackLimit();
|
||||
|
||||
inline int char_size() { return static_cast<int>(mode_); }
|
||||
inline js::jit::Scale factor() {
|
||||
return mode_ == UC16 ? js::jit::TimesTwo : js::jit::TimesOne;
|
||||
|
@ -86,8 +103,11 @@ class SMRegExpMacroAssembler final : public NativeRegExpMacroAssembler {
|
|||
|
||||
js::jit::Label entry_label_;
|
||||
js::jit::Label start_label_;
|
||||
js::jit::Label backtrack_label_;
|
||||
js::jit::Label success_label_;
|
||||
js::jit::Label exit_label_;
|
||||
js::jit::Label stack_overflow_label_;
|
||||
js::jit::Label exit_with_exception_label_;
|
||||
|
||||
Mode mode_;
|
||||
int num_registers_;
|
||||
|
|
|
@ -16,10 +16,13 @@
|
|||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
using js::jit::AbsoluteAddress;
|
||||
using js::jit::Address;
|
||||
using js::jit::AllocatableGeneralRegisterSet;
|
||||
using js::jit::Assembler;
|
||||
using js::jit::GeneralRegisterSet;
|
||||
using js::jit::Imm32;
|
||||
using js::jit::ImmPtr;
|
||||
using js::jit::ImmWord;
|
||||
using js::jit::Register;
|
||||
using js::jit::StackMacroAssembler;
|
||||
|
@ -62,13 +65,48 @@ void SMRegExpMacroAssembler::AdvanceCurrentPosition(int by) {
|
|||
}
|
||||
}
|
||||
|
||||
void SMRegExpMacroAssembler::Backtrack() {
|
||||
// Check for an interrupt. We have to restart from the beginning if we
|
||||
// are interrupted, so we only check for urgent interrupts.
|
||||
js::jit::Label noInterrupt;
|
||||
masm_.branchTest32(
|
||||
Assembler::Zero, AbsoluteAddress(cx_->addressOfInterruptBits()),
|
||||
Imm32(uint32_t(js::InterruptReason::CallbackUrgent)), &noInterrupt);
|
||||
masm_.movePtr(ImmWord(js::RegExpRunStatus_Error), temp0_);
|
||||
masm_.jump(&exit_label_);
|
||||
masm_.bind(&noInterrupt);
|
||||
|
||||
// Pop code location from backtrack stack and jump to location.
|
||||
Pop(temp0_);
|
||||
masm_.jump(temp0_);
|
||||
}
|
||||
|
||||
void SMRegExpMacroAssembler::Bind(Label* label) {
|
||||
masm_.bind(label->inner());
|
||||
}
|
||||
|
||||
void SMRegExpMacroAssembler::Fail() {
|
||||
masm_.movePtr(ImmWord(js::RegExpRunStatus_Success_NotFound), temp0_);
|
||||
masm_.jump(&exit_label_);
|
||||
}
|
||||
|
||||
void SMRegExpMacroAssembler::GoTo(Label* to) {
|
||||
masm_.jump(LabelOrBacktrack(to));
|
||||
}
|
||||
|
||||
void SMRegExpMacroAssembler::PopCurrentPosition() { Pop(current_position_); }
|
||||
|
||||
void SMRegExpMacroAssembler::PushBacktrack(Label* label) {
|
||||
MOZ_ASSERT(!label->is_bound());
|
||||
MOZ_ASSERT(!label->patchOffset_.bound());
|
||||
label->patchOffset_ = masm_.movWithPatch(ImmPtr(nullptr), temp0_);
|
||||
MOZ_ASSERT(label->patchOffset_.bound());
|
||||
|
||||
Push(temp0_);
|
||||
|
||||
CheckBacktrackStackLimit();
|
||||
}
|
||||
|
||||
void SMRegExpMacroAssembler::PushCurrentPosition() { Push(current_position_); }
|
||||
|
||||
// Returns true if a regexp match can be restarted (aka the regexp is global).
|
||||
|
@ -92,6 +130,32 @@ void SMRegExpMacroAssembler::Pop(Register target) {
|
|||
masm_.addPtr(Imm32(sizeof(void*)), backtrack_stack_pointer_);
|
||||
}
|
||||
|
||||
void SMRegExpMacroAssembler::JumpOrBacktrack(Label* to) {
|
||||
if (to) {
|
||||
masm_.jump(to->inner());
|
||||
} else {
|
||||
Backtrack();
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a quick inline test for backtrack stack overflow.
|
||||
// If the test fails, call an OOL handler to try growing the stack.
|
||||
void SMRegExpMacroAssembler::CheckBacktrackStackLimit() {
|
||||
js::jit::Label no_stack_overflow;
|
||||
masm_.branchPtr(
|
||||
Assembler::BelowOrEqual,
|
||||
AbsoluteAddress(isolate()->regexp_stack()->limit_address_address()),
|
||||
backtrack_stack_pointer_, &no_stack_overflow);
|
||||
|
||||
masm_.call(&stack_overflow_label_);
|
||||
|
||||
// Exit with an exception if the call failed
|
||||
masm_.branchTest32(Assembler::Zero, temp0_, temp0_,
|
||||
&exit_with_exception_label_);
|
||||
|
||||
masm_.bind(&no_stack_overflow);
|
||||
}
|
||||
|
||||
// This is only used by tracing code.
|
||||
// The return value doesn't matter.
|
||||
RegExpMacroAssembler::IrregexpImplementation
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "new-regexp/regexp-shim.h"
|
||||
#include "new-regexp/regexp-stack.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -150,6 +151,10 @@ std::unique_ptr<char[]> String::ToCString() {
|
|||
return std::unique_ptr<char[]>();
|
||||
}
|
||||
|
||||
byte* Isolate::top_of_regexp_stack() const {
|
||||
return reinterpret_cast<byte*>(regexpStack_->memory_top_address_address());
|
||||
}
|
||||
|
||||
Handle<ByteArray> Isolate::NewByteArray(int length, AllocationType alloc) {
|
||||
MOZ_RELEASE_ASSERT(length >= 0);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <cctype>
|
||||
|
||||
#include "jit/Label.h"
|
||||
#include "jit/shared/Assembler-shared.h"
|
||||
#include "js/Value.h"
|
||||
#include "new-regexp/util/flags.h"
|
||||
#include "new-regexp/util/vector.h"
|
||||
|
@ -974,9 +975,9 @@ using Factory = Isolate;
|
|||
class Isolate {
|
||||
public:
|
||||
//********** Isolate code **********//
|
||||
RegExpStack* regexp_stack() const { return regexp_stack_; }
|
||||
bool has_pending_exception() { return cx()->isExceptionPending(); }
|
||||
void StackOverflow() { js::ReportOverRecursed(cx()); }
|
||||
RegExpStack* regexp_stack() const { return regexpStack_; }
|
||||
byte* top_of_regexp_stack() const;
|
||||
void StackOverflow() {}
|
||||
|
||||
#ifndef V8_INTL_SUPPORT
|
||||
unibrow::Mapping<unibrow::Ecma262UnCanonicalize>* jsregexp_uncanonicalize() {
|
||||
|
@ -1055,7 +1056,7 @@ private:
|
|||
friend class HandleScope;
|
||||
|
||||
JSContext* cx_;
|
||||
RegExpStack* regexp_stack_;
|
||||
RegExpStack* regexpStack_;
|
||||
Counters counters_;
|
||||
};
|
||||
|
||||
|
@ -1113,7 +1114,7 @@ class Label {
|
|||
public:
|
||||
Label() : inner_(js::jit::Label()) {}
|
||||
|
||||
operator js::jit::Label*() { return &inner_; }
|
||||
js::jit::Label* inner() { return &inner_; }
|
||||
|
||||
void Unuse() { inner_.reset(); }
|
||||
|
||||
|
@ -1127,6 +1128,9 @@ class Label {
|
|||
|
||||
private:
|
||||
js::jit::Label inner_;
|
||||
js::jit::CodeOffset patchOffset_;
|
||||
|
||||
friend class SMRegExpMacroAssembler;
|
||||
};
|
||||
|
||||
// TODO: Map flags to jitoptions
|
||||
|
|
Загрузка…
Ссылка в новой задаче