f31b7928ae
See https://github.com/tc39/proposal-regexp-lookbehind for a high-level description of the feature and examples. This is one of the features requested in https://github.com/dart-lang/sdk/issues/34935. This work takes the feature as present in the v8 engine and appropriately merges it into our irregexp fork. Notable changes to the irregexp codebase to introduce this feature: ----- We can no longer assume that all matching proceeds forwards, since lookbehind matching proceeds backwards. Similarly, we cannot assume that we can only be at the start of a string if we started matching from that point. The direction of matching must also be taken into consideration when doing bounds checking, which previously assumed the engine would never attempt to look before the start of a string. ----- We may now parse backreferences to captures before the capture they reference, since we parse regular expressions left to right, but lookbehinds perform captures as they evaluate the string from right to left. Since RegExpBackReference objects contain a pointer to their corresponding capture, this means that we may need to create RegExpCapture objects prior to the parsing of the corresponding captured subexpression. Thus, RegExpCapture objects are now only initialized with their index, and the body is set later when the subexpression is encountered and parsed. This means any method that operates on the body of a RegExpCapture can no longer be const, which also affects the rest of the RegExpTree class hierarchy. This also means that we don't have a valid max_match length for backreferences based off the capture body, and must assume they can end up being any length. ----- Change-Id: Iffe0e71b17b1a0c6fea77235e8aee5c093005811 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/94540 Commit-Queue: Stevie Strickland <sstrickl@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
146 lines
6.4 KiB
C++
146 lines
6.4 KiB
C++
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef RUNTIME_VM_REGEXP_ASSEMBLER_BYTECODE_H_
|
|
#define RUNTIME_VM_REGEXP_ASSEMBLER_BYTECODE_H_
|
|
|
|
#include "vm/object.h"
|
|
#include "vm/regexp_assembler.h"
|
|
|
|
namespace dart {
|
|
|
|
class BytecodeRegExpMacroAssembler : public RegExpMacroAssembler {
|
|
public:
|
|
// Create an assembler. Instructions and relocation information are emitted
|
|
// into a buffer, with the instructions starting from the beginning and the
|
|
// relocation information starting from the end of the buffer. See CodeDesc
|
|
// for a detailed comment on the layout (globals.h).
|
|
//
|
|
// If the provided buffer is NULL, the assembler allocates and grows its own
|
|
// buffer, and buffer_size determines the initial buffer size. The buffer is
|
|
// owned by the assembler and deallocated upon destruction of the assembler.
|
|
//
|
|
// If the provided buffer is not NULL, the assembler uses the provided buffer
|
|
// for code generation and assumes its size to be buffer_size. If the buffer
|
|
// is too small, a fatal error occurs. No deallocation of the buffer is done
|
|
// upon destruction of the assembler.
|
|
BytecodeRegExpMacroAssembler(ZoneGrowableArray<uint8_t>* buffer, Zone* zone);
|
|
virtual ~BytecodeRegExpMacroAssembler();
|
|
|
|
// The byte-code interpreter checks on each push anyway.
|
|
virtual intptr_t stack_limit_slack() { return 1; }
|
|
virtual bool CanReadUnaligned() { return false; }
|
|
virtual void BindBlock(BlockLabel* label);
|
|
virtual void AdvanceCurrentPosition(intptr_t by); // Signed cp change.
|
|
virtual void PopCurrentPosition();
|
|
virtual void PushCurrentPosition();
|
|
virtual void Backtrack();
|
|
virtual void GoTo(BlockLabel* label);
|
|
virtual void PushBacktrack(BlockLabel* label);
|
|
virtual bool Succeed();
|
|
virtual void Fail();
|
|
virtual void PopRegister(intptr_t register_index);
|
|
virtual void PushRegister(intptr_t register_index);
|
|
virtual void AdvanceRegister(intptr_t reg, intptr_t by); // r[reg] += by.
|
|
virtual void SetCurrentPositionFromEnd(intptr_t by);
|
|
virtual void SetRegister(intptr_t register_index, intptr_t to);
|
|
virtual void WriteCurrentPositionToRegister(intptr_t reg, intptr_t cp_offset);
|
|
virtual void ClearRegisters(intptr_t reg_from, intptr_t reg_to);
|
|
virtual void ReadCurrentPositionFromRegister(intptr_t reg);
|
|
virtual void WriteStackPointerToRegister(intptr_t reg);
|
|
virtual void ReadStackPointerFromRegister(intptr_t reg);
|
|
virtual void LoadCurrentCharacter(intptr_t cp_offset,
|
|
BlockLabel* on_end_of_input,
|
|
bool check_bounds = true,
|
|
intptr_t characters = 1);
|
|
virtual void CheckCharacter(unsigned c, BlockLabel* on_equal);
|
|
virtual void CheckCharacterAfterAnd(unsigned c,
|
|
unsigned mask,
|
|
BlockLabel* on_equal);
|
|
virtual void CheckCharacterGT(uint16_t limit, BlockLabel* on_greater);
|
|
virtual void CheckCharacterLT(uint16_t limit, BlockLabel* on_less);
|
|
virtual void CheckGreedyLoop(BlockLabel* on_tos_equals_current_position);
|
|
virtual void CheckAtStart(BlockLabel* on_at_start);
|
|
virtual void CheckNotAtStart(intptr_t cp_offset, BlockLabel* on_not_at_start);
|
|
virtual void CheckNotCharacter(unsigned c, BlockLabel* on_not_equal);
|
|
virtual void CheckNotCharacterAfterAnd(unsigned c,
|
|
unsigned mask,
|
|
BlockLabel* on_not_equal);
|
|
virtual void CheckNotCharacterAfterMinusAnd(uint16_t c,
|
|
uint16_t minus,
|
|
uint16_t mask,
|
|
BlockLabel* on_not_equal);
|
|
virtual void CheckCharacterInRange(uint16_t from,
|
|
uint16_t to,
|
|
BlockLabel* on_in_range);
|
|
virtual void CheckCharacterNotInRange(uint16_t from,
|
|
uint16_t to,
|
|
BlockLabel* on_not_in_range);
|
|
virtual void CheckBitInTable(const TypedData& table, BlockLabel* on_bit_set);
|
|
virtual void CheckNotBackReference(intptr_t start_reg,
|
|
bool read_backward,
|
|
BlockLabel* on_no_match);
|
|
virtual void CheckNotBackReferenceIgnoreCase(intptr_t start_reg,
|
|
bool read_backward,
|
|
BlockLabel* on_no_match);
|
|
virtual void IfRegisterLT(intptr_t register_index,
|
|
intptr_t comparand,
|
|
BlockLabel* if_lt);
|
|
virtual void IfRegisterGE(intptr_t register_index,
|
|
intptr_t comparand,
|
|
BlockLabel* if_ge);
|
|
virtual void IfRegisterEqPos(intptr_t register_index, BlockLabel* if_eq);
|
|
|
|
virtual IrregexpImplementation Implementation();
|
|
// virtual Handle<HeapObject> GetCode(Handle<String> source);
|
|
RawTypedData* GetBytecode();
|
|
|
|
// New
|
|
virtual bool IsClosed() const {
|
|
// Added by Dart for the IR version. Bytecode version should never need an
|
|
// extra goto.
|
|
return true;
|
|
}
|
|
virtual void Print(const char* str) { UNIMPLEMENTED(); }
|
|
virtual void PrintBlocks() { UNIMPLEMENTED(); }
|
|
/////
|
|
|
|
static RawInstance* Interpret(const RegExp& regexp,
|
|
const String& str,
|
|
const Smi& start_index,
|
|
bool is_sticky,
|
|
Zone* zone);
|
|
|
|
private:
|
|
void Expand();
|
|
// Code and bitmap emission.
|
|
inline void EmitOrLink(BlockLabel* label);
|
|
inline void Emit32(uint32_t x);
|
|
inline void Emit16(uint32_t x);
|
|
inline void Emit8(uint32_t x);
|
|
inline void Emit(uint32_t bc, uint32_t arg);
|
|
// Bytecode buffer.
|
|
intptr_t length();
|
|
|
|
// The buffer into which code and relocation info are generated.
|
|
ZoneGrowableArray<uint8_t>* buffer_;
|
|
|
|
// The program counter.
|
|
intptr_t pc_;
|
|
|
|
BlockLabel backtrack_;
|
|
|
|
intptr_t advance_current_start_;
|
|
intptr_t advance_current_offset_;
|
|
intptr_t advance_current_end_;
|
|
|
|
static const int kInvalidPC = -1;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(BytecodeRegExpMacroAssembler);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_REGEXP_ASSEMBLER_BYTECODE_H_
|