2015-07-07 21:43:32 +00:00
|
|
|
// Copyright (c) 2014, 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.
|
|
|
|
|
2016-10-26 07:26:03 +00:00
|
|
|
#ifndef RUNTIME_VM_REGEXP_ASSEMBLER_IR_H_
|
|
|
|
#define RUNTIME_VM_REGEXP_ASSEMBLER_IR_H_
|
2015-07-07 21:43:32 +00:00
|
|
|
|
2017-09-04 14:18:37 +00:00
|
|
|
#include "vm/compiler/assembler/assembler.h"
|
|
|
|
#include "vm/compiler/backend/il.h"
|
2015-07-07 21:43:32 +00:00
|
|
|
#include "vm/object.h"
|
|
|
|
#include "vm/regexp_assembler.h"
|
|
|
|
|
|
|
|
namespace dart {
|
|
|
|
|
|
|
|
class IRRegExpMacroAssembler : public RegExpMacroAssembler {
|
|
|
|
public:
|
|
|
|
// Type of input string to generate code for.
|
|
|
|
enum Mode { ASCII = 1, UC16 = 2 };
|
|
|
|
|
|
|
|
// Result of calling generated native RegExp code.
|
|
|
|
// RETRY: Something significant changed during execution, and the matching
|
|
|
|
// should be retried from scratch.
|
|
|
|
// EXCEPTION: Something failed during execution. If no exception has been
|
|
|
|
// thrown, it's an internal out-of-memory, and the caller should
|
|
|
|
// throw the exception.
|
|
|
|
// FAILURE: Matching failed.
|
|
|
|
// SUCCESS: Matching succeeded, and the output array has been filled with
|
|
|
|
// capture positions.
|
|
|
|
enum Result { RETRY = -2, EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 };
|
|
|
|
|
|
|
|
IRRegExpMacroAssembler(intptr_t specialization_cid,
|
|
|
|
intptr_t capture_count,
|
|
|
|
const ParsedFunction* parsed_function,
|
|
|
|
const ZoneGrowableArray<const ICData*>& ic_data_array,
|
2017-06-23 10:51:52 +00:00
|
|
|
intptr_t osr_id,
|
2015-07-07 21:43:32 +00:00
|
|
|
Zone* zone);
|
|
|
|
virtual ~IRRegExpMacroAssembler();
|
|
|
|
|
|
|
|
virtual bool CanReadUnaligned();
|
|
|
|
|
2016-03-22 00:21:05 +00:00
|
|
|
static RawArray* Execute(const RegExp& regexp,
|
2015-07-07 21:43:32 +00:00
|
|
|
const String& input,
|
|
|
|
const Smi& start_offset,
|
2016-11-17 16:46:21 +00:00
|
|
|
bool sticky,
|
2015-07-07 21:43:32 +00:00
|
|
|
Zone* zone);
|
|
|
|
|
|
|
|
virtual bool IsClosed() const { return (current_instruction_ == NULL); }
|
|
|
|
|
|
|
|
virtual intptr_t stack_limit_slack();
|
|
|
|
virtual void AdvanceCurrentPosition(intptr_t by);
|
|
|
|
virtual void AdvanceRegister(intptr_t reg, intptr_t by);
|
|
|
|
virtual void Backtrack();
|
|
|
|
virtual void BindBlock(BlockLabel* label);
|
|
|
|
virtual void CheckAtStart(BlockLabel* on_at_start);
|
|
|
|
virtual void CheckCharacter(uint32_t c, BlockLabel* on_equal);
|
|
|
|
virtual void CheckCharacterAfterAnd(uint32_t c,
|
|
|
|
uint32_t mask,
|
|
|
|
BlockLabel* on_equal);
|
|
|
|
virtual void CheckCharacterGT(uint16_t limit, BlockLabel* on_greater);
|
|
|
|
virtual void CheckCharacterLT(uint16_t limit, BlockLabel* on_less);
|
|
|
|
// A "greedy loop" is a loop that is both greedy and with a simple
|
|
|
|
// body. It has a particularly simple implementation.
|
|
|
|
virtual void CheckGreedyLoop(BlockLabel* on_tos_equals_current_position);
|
[VM] Adding regexp lookbehind assertion support.
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>
2019-03-14 14:26:47 +00:00
|
|
|
virtual void CheckNotAtStart(intptr_t cp_offset, BlockLabel* on_not_at_start);
|
2015-07-07 21:43:32 +00:00
|
|
|
virtual void CheckNotBackReference(intptr_t start_reg,
|
[VM] Adding regexp lookbehind assertion support.
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>
2019-03-14 14:26:47 +00:00
|
|
|
bool read_backward,
|
2015-07-07 21:43:32 +00:00
|
|
|
BlockLabel* on_no_match);
|
|
|
|
virtual void CheckNotBackReferenceIgnoreCase(intptr_t start_reg,
|
[VM] Adding regexp lookbehind assertion support.
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>
2019-03-14 14:26:47 +00:00
|
|
|
bool read_backward,
|
2019-04-29 09:11:48 +00:00
|
|
|
bool unicode,
|
2015-07-07 21:43:32 +00:00
|
|
|
BlockLabel* on_no_match);
|
|
|
|
virtual void CheckNotCharacter(uint32_t c, BlockLabel* on_not_equal);
|
|
|
|
virtual void CheckNotCharacterAfterAnd(uint32_t c,
|
|
|
|
uint32_t 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);
|
|
|
|
|
|
|
|
// Checks whether the given offset from the current position is before
|
|
|
|
// the end of the string.
|
|
|
|
virtual void CheckPosition(intptr_t cp_offset, BlockLabel* on_outside_input);
|
2016-11-08 21:54:47 +00:00
|
|
|
virtual bool CheckSpecialCharacterClass(uint16_t type,
|
|
|
|
BlockLabel* on_no_match);
|
2015-07-07 21:43:32 +00:00
|
|
|
virtual void Fail();
|
|
|
|
virtual void IfRegisterGE(intptr_t reg,
|
2016-11-08 21:54:47 +00:00
|
|
|
intptr_t comparand,
|
|
|
|
BlockLabel* if_ge);
|
2015-07-07 21:43:32 +00:00
|
|
|
virtual void IfRegisterLT(intptr_t reg,
|
2016-11-08 21:54:47 +00:00
|
|
|
intptr_t comparand,
|
|
|
|
BlockLabel* if_lt);
|
2015-07-07 21:43:32 +00:00
|
|
|
virtual void IfRegisterEqPos(intptr_t reg, BlockLabel* if_eq);
|
|
|
|
virtual IrregexpImplementation Implementation();
|
|
|
|
virtual void GoTo(BlockLabel* to);
|
|
|
|
virtual void LoadCurrentCharacter(intptr_t cp_offset,
|
|
|
|
BlockLabel* on_end_of_input,
|
|
|
|
bool check_bounds = true,
|
|
|
|
intptr_t characters = 1);
|
|
|
|
virtual void PopCurrentPosition();
|
|
|
|
virtual void PopRegister(intptr_t register_index);
|
|
|
|
virtual void Print(const char* str);
|
|
|
|
virtual void PushBacktrack(BlockLabel* label);
|
|
|
|
virtual void PushCurrentPosition();
|
|
|
|
virtual void PushRegister(intptr_t register_index);
|
|
|
|
virtual void ReadCurrentPositionFromRegister(intptr_t reg);
|
|
|
|
virtual void ReadStackPointerFromRegister(intptr_t reg);
|
|
|
|
virtual void SetCurrentPositionFromEnd(intptr_t by);
|
|
|
|
virtual void SetRegister(intptr_t register_index, intptr_t to);
|
|
|
|
virtual bool Succeed();
|
|
|
|
virtual void WriteCurrentPositionToRegister(intptr_t reg, intptr_t cp_offset);
|
|
|
|
virtual void ClearRegisters(intptr_t reg_from, intptr_t reg_to);
|
|
|
|
virtual void WriteStackPointerToRegister(intptr_t reg);
|
|
|
|
|
|
|
|
virtual void PrintBlocks();
|
|
|
|
|
|
|
|
IndirectGotoInstr* backtrack_goto() const { return backtrack_goto_; }
|
|
|
|
GraphEntryInstr* graph_entry() const { return entry_block_; }
|
|
|
|
|
|
|
|
intptr_t num_stack_locals() const { return local_id_.Count(); }
|
|
|
|
intptr_t num_blocks() const { return block_id_.Count(); }
|
|
|
|
|
|
|
|
// Generate a dispatch block implementing backtracking. Must be done after
|
|
|
|
// graph construction.
|
|
|
|
void GenerateBacktrackBlock();
|
|
|
|
|
|
|
|
// Allocate the actual registers array once its size is known. Must be done
|
|
|
|
// after graph construction.
|
|
|
|
void FinalizeRegistersArray();
|
|
|
|
|
|
|
|
private:
|
2018-09-03 16:01:24 +00:00
|
|
|
intptr_t GetNextDeoptId() const {
|
|
|
|
return thread_->compiler_state().GetNextDeoptId();
|
|
|
|
}
|
2017-05-25 17:12:19 +00:00
|
|
|
|
2015-07-07 21:43:32 +00:00
|
|
|
// Generate the contents of preset blocks. The entry block is the entry point
|
|
|
|
// of the generated code.
|
|
|
|
void GenerateEntryBlock();
|
|
|
|
// Copies capture indices into the result area and returns true.
|
|
|
|
void GenerateSuccessBlock();
|
|
|
|
// Returns false.
|
|
|
|
void GenerateExitBlock();
|
|
|
|
|
|
|
|
enum ComparisonKind {
|
|
|
|
kEQ,
|
|
|
|
kNE,
|
|
|
|
kLT,
|
|
|
|
kGT,
|
|
|
|
kLTE,
|
|
|
|
kGTE,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct InstanceCallDescriptor {
|
|
|
|
// Standard (i.e. most non-Smi) functions.
|
|
|
|
explicit InstanceCallDescriptor(const String& name)
|
2016-11-08 21:54:47 +00:00
|
|
|
: name(name), token_kind(Token::kILLEGAL), checked_argument_count(1) {}
|
2015-07-07 21:43:32 +00:00
|
|
|
|
|
|
|
InstanceCallDescriptor(const String& name,
|
|
|
|
Token::Kind token_kind,
|
|
|
|
intptr_t checked_argument_count)
|
2016-11-08 21:54:47 +00:00
|
|
|
: name(name),
|
|
|
|
token_kind(token_kind),
|
|
|
|
checked_argument_count(checked_argument_count) {}
|
2015-07-07 21:43:32 +00:00
|
|
|
|
|
|
|
// Special cases for Smi and indexing functions.
|
|
|
|
static InstanceCallDescriptor FromToken(Token::Kind token_kind) {
|
|
|
|
switch (token_kind) {
|
2016-11-08 21:54:47 +00:00
|
|
|
case Token::kEQ:
|
|
|
|
return InstanceCallDescriptor(Symbols::EqualOperator(), token_kind,
|
|
|
|
2);
|
|
|
|
case Token::kADD:
|
|
|
|
return InstanceCallDescriptor(Symbols::Plus(), token_kind, 2);
|
|
|
|
case Token::kSUB:
|
|
|
|
return InstanceCallDescriptor(Symbols::Minus(), token_kind, 2);
|
|
|
|
case Token::kBIT_OR:
|
|
|
|
return InstanceCallDescriptor(Symbols::BitOr(), token_kind, 2);
|
|
|
|
case Token::kBIT_AND:
|
|
|
|
return InstanceCallDescriptor(Symbols::BitAnd(), token_kind, 2);
|
|
|
|
case Token::kLT:
|
|
|
|
return InstanceCallDescriptor(Symbols::LAngleBracket(), token_kind,
|
|
|
|
2);
|
|
|
|
case Token::kLTE:
|
|
|
|
return InstanceCallDescriptor(Symbols::LessEqualOperator(),
|
|
|
|
token_kind, 2);
|
|
|
|
case Token::kGT:
|
|
|
|
return InstanceCallDescriptor(Symbols::RAngleBracket(), token_kind,
|
|
|
|
2);
|
|
|
|
case Token::kGTE:
|
|
|
|
return InstanceCallDescriptor(Symbols::GreaterEqualOperator(),
|
|
|
|
token_kind, 2);
|
|
|
|
case Token::kNEGATE:
|
|
|
|
return InstanceCallDescriptor(Symbols::UnaryMinus(), token_kind, 1);
|
|
|
|
case Token::kINDEX:
|
|
|
|
return InstanceCallDescriptor(Symbols::IndexToken(), token_kind, 2);
|
|
|
|
case Token::kASSIGN_INDEX:
|
|
|
|
return InstanceCallDescriptor(Symbols::AssignIndexToken(), token_kind,
|
|
|
|
2);
|
2015-07-07 21:43:32 +00:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return InstanceCallDescriptor(Symbols::Empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
const String& name;
|
|
|
|
Token::Kind token_kind;
|
|
|
|
intptr_t checked_argument_count;
|
|
|
|
};
|
|
|
|
|
|
|
|
LocalVariable* Local(const String& name);
|
|
|
|
LocalVariable* Parameter(const String& name, intptr_t index) const;
|
|
|
|
|
|
|
|
ConstantInstr* Int64Constant(int64_t value) const;
|
|
|
|
ConstantInstr* Uint64Constant(uint64_t value) const;
|
|
|
|
ConstantInstr* BoolConstant(bool value) const;
|
|
|
|
ConstantInstr* StringConstant(const char* value) const;
|
|
|
|
|
|
|
|
// The word character map static member of the RegExp class.
|
|
|
|
// Byte map of one byte characters with a 0xff if the character is a word
|
|
|
|
// character (digit, letter or underscore) and 0x00 otherwise.
|
|
|
|
// Used by generated RegExp code.
|
|
|
|
ConstantInstr* WordCharacterMapConstant() const;
|
|
|
|
|
|
|
|
ComparisonInstr* Comparison(ComparisonKind kind,
|
|
|
|
PushArgumentInstr* lhs,
|
|
|
|
PushArgumentInstr* rhs);
|
|
|
|
ComparisonInstr* Comparison(ComparisonKind kind,
|
|
|
|
Definition* lhs,
|
|
|
|
Definition* rhs);
|
|
|
|
|
|
|
|
InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc,
|
|
|
|
PushArgumentInstr* arg1) const;
|
|
|
|
InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc,
|
|
|
|
PushArgumentInstr* arg1,
|
|
|
|
PushArgumentInstr* arg2) const;
|
|
|
|
InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc,
|
|
|
|
PushArgumentInstr* arg1,
|
|
|
|
PushArgumentInstr* arg2,
|
|
|
|
PushArgumentInstr* arg3) const;
|
|
|
|
InstanceCallInstr* InstanceCall(
|
|
|
|
const InstanceCallDescriptor& desc,
|
|
|
|
ZoneGrowableArray<PushArgumentInstr*>* arguments) const;
|
|
|
|
|
|
|
|
StaticCallInstr* StaticCall(const Function& function,
|
2017-09-28 19:43:32 +00:00
|
|
|
ICData::RebindRule rebind_rule) const;
|
2015-07-07 21:43:32 +00:00
|
|
|
StaticCallInstr* StaticCall(const Function& function,
|
|
|
|
PushArgumentInstr* arg1,
|
2017-09-28 19:43:32 +00:00
|
|
|
ICData::RebindRule rebind_rule) const;
|
|
|
|
StaticCallInstr* StaticCall(const Function& function,
|
|
|
|
PushArgumentInstr* arg1,
|
|
|
|
PushArgumentInstr* arg2,
|
|
|
|
ICData::RebindRule rebind_rule) const;
|
|
|
|
StaticCallInstr* StaticCall(const Function& function,
|
|
|
|
ZoneGrowableArray<PushArgumentInstr*>* arguments,
|
|
|
|
ICData::RebindRule rebind_rule) const;
|
2015-07-07 21:43:32 +00:00
|
|
|
|
|
|
|
// Creates a new block consisting simply of a goto to dst.
|
|
|
|
TargetEntryInstr* TargetWithJoinGoto(JoinEntryInstr* dst);
|
|
|
|
IndirectEntryInstr* IndirectWithJoinGoto(JoinEntryInstr* dst);
|
|
|
|
|
|
|
|
// Adds, respectively subtracts lhs and rhs and returns the result.
|
|
|
|
Definition* Add(PushArgumentInstr* lhs, PushArgumentInstr* rhs);
|
|
|
|
Definition* Sub(PushArgumentInstr* lhs, PushArgumentInstr* rhs);
|
|
|
|
|
|
|
|
LoadLocalInstr* LoadLocal(LocalVariable* local) const;
|
|
|
|
void StoreLocal(LocalVariable* local, Value* value);
|
|
|
|
|
|
|
|
PushArgumentInstr* PushArgument(Value* value);
|
|
|
|
PushArgumentInstr* PushLocal(LocalVariable* local);
|
|
|
|
|
|
|
|
PushArgumentInstr* PushRegisterIndex(intptr_t reg);
|
|
|
|
Value* LoadRegister(intptr_t reg);
|
|
|
|
void StoreRegister(intptr_t reg, intptr_t value);
|
|
|
|
void StoreRegister(PushArgumentInstr* registers,
|
|
|
|
PushArgumentInstr* index,
|
|
|
|
PushArgumentInstr* value);
|
|
|
|
|
|
|
|
// Load a number of characters at the given offset from the
|
|
|
|
// current position, into the current-character register.
|
|
|
|
void LoadCurrentCharacterUnchecked(intptr_t cp_offset,
|
|
|
|
intptr_t character_count);
|
|
|
|
|
|
|
|
// Returns the character within the passed string at the specified index.
|
|
|
|
Value* CharacterAt(LocalVariable* index);
|
|
|
|
|
|
|
|
// Load a number of characters starting from index in the pattern string.
|
|
|
|
Value* LoadCodeUnitsAt(LocalVariable* index, intptr_t character_count);
|
|
|
|
|
2017-06-23 10:51:52 +00:00
|
|
|
// Check whether preemption has been requested. Also serves as an OSR entry.
|
|
|
|
void CheckPreemption(bool is_backtrack);
|
2015-07-07 21:43:32 +00:00
|
|
|
|
|
|
|
// Byte size of chars in the string to match (decided by the Mode argument)
|
|
|
|
inline intptr_t char_size() { return static_cast<int>(mode_); }
|
|
|
|
|
|
|
|
// Equivalent to a conditional branch to the label, unless the label
|
|
|
|
// is NULL, in which case it is a conditional Backtrack.
|
|
|
|
void BranchOrBacktrack(ComparisonInstr* comparison,
|
|
|
|
BlockLabel* true_successor);
|
|
|
|
|
|
|
|
// Set up all local variables and parameters.
|
|
|
|
void InitializeLocals();
|
|
|
|
|
|
|
|
// Allocates a new local, and returns the appropriate id for placing it
|
|
|
|
// on the stack.
|
|
|
|
intptr_t GetNextLocalIndex();
|
|
|
|
|
|
|
|
// We never have any copied parameters.
|
2016-11-08 21:54:47 +00:00
|
|
|
intptr_t num_copied_params() const { return 0; }
|
2015-07-07 21:43:32 +00:00
|
|
|
|
|
|
|
// Return the position register at the specified index, creating it if
|
|
|
|
// necessary. Note that the number of such registers can exceed the amount
|
|
|
|
// required by the number of output captures.
|
|
|
|
LocalVariable* position_register(intptr_t index);
|
|
|
|
|
|
|
|
void set_current_instruction(Instruction* instruction);
|
|
|
|
|
|
|
|
// The following functions are responsible for appending instructions
|
|
|
|
// to the current instruction in various ways. The most simple one
|
|
|
|
// is AppendInstruction, which simply appends an instruction and performs
|
|
|
|
// bookkeeping.
|
|
|
|
void AppendInstruction(Instruction* instruction);
|
|
|
|
// Similar to AppendInstruction, but closes the current block by
|
|
|
|
// setting current_instruction_ to NULL.
|
|
|
|
void CloseBlockWith(Instruction* instruction);
|
|
|
|
// Appends definition and allocates a temp index for the result.
|
|
|
|
Value* Bind(Definition* definition);
|
|
|
|
// Loads and binds a local variable.
|
|
|
|
Value* BindLoadLocal(const LocalVariable& local);
|
|
|
|
|
|
|
|
// Appends the definition.
|
|
|
|
void Do(Definition* definition);
|
|
|
|
// Closes the current block with a jump to the specified block.
|
|
|
|
void GoTo(JoinEntryInstr* to);
|
|
|
|
|
|
|
|
// Accessors for our local stack_.
|
|
|
|
void PushStack(Definition* definition);
|
|
|
|
Definition* PopStack();
|
|
|
|
Definition* PeekStack();
|
|
|
|
void CheckStackLimit();
|
|
|
|
void GrowStack();
|
|
|
|
|
|
|
|
// Prints the specified argument. Used for debugging.
|
|
|
|
void Print(PushArgumentInstr* argument);
|
|
|
|
|
|
|
|
// A utility class tracking ids of various objects such as blocks, temps, etc.
|
|
|
|
class IdAllocator : public ValueObject {
|
|
|
|
public:
|
2017-06-23 10:51:52 +00:00
|
|
|
explicit IdAllocator(intptr_t first_id = 0) : next_id(first_id) {}
|
2015-07-07 21:43:32 +00:00
|
|
|
|
|
|
|
intptr_t Count() const { return next_id; }
|
|
|
|
intptr_t Alloc(intptr_t count = 1) {
|
|
|
|
ASSERT(count >= 0);
|
|
|
|
intptr_t current_id = next_id;
|
|
|
|
next_id += count;
|
|
|
|
return current_id;
|
|
|
|
}
|
|
|
|
void Dealloc(intptr_t count = 1) {
|
|
|
|
ASSERT(count <= next_id);
|
|
|
|
next_id -= count;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
intptr_t next_id;
|
|
|
|
};
|
|
|
|
|
2017-05-25 17:12:19 +00:00
|
|
|
Thread* thread_;
|
|
|
|
|
2015-07-07 21:43:32 +00:00
|
|
|
// Which mode to generate code for (ASCII or UC16).
|
|
|
|
Mode mode_;
|
|
|
|
|
|
|
|
// Which specific string class to generate code for.
|
|
|
|
intptr_t specialization_cid_;
|
|
|
|
|
|
|
|
// Block entries used internally.
|
|
|
|
GraphEntryInstr* entry_block_;
|
|
|
|
JoinEntryInstr* start_block_;
|
|
|
|
JoinEntryInstr* success_block_;
|
|
|
|
JoinEntryInstr* exit_block_;
|
|
|
|
|
|
|
|
// Shared backtracking block.
|
|
|
|
JoinEntryInstr* backtrack_block_;
|
|
|
|
// Single indirect goto instruction which performs all backtracking.
|
|
|
|
IndirectGotoInstr* backtrack_goto_;
|
|
|
|
|
|
|
|
const ParsedFunction* parsed_function_;
|
|
|
|
const ZoneGrowableArray<const ICData*>& ic_data_array_;
|
|
|
|
|
|
|
|
// All created blocks are contained within this set. Used for printing
|
|
|
|
// the generated code.
|
|
|
|
GrowableArray<BlockEntryInstr*> blocks_;
|
|
|
|
|
|
|
|
// The current instruction to link to when new code is emitted.
|
|
|
|
Instruction* current_instruction_;
|
|
|
|
|
|
|
|
// A list, acting as the runtime stack for both backtrack locations and
|
|
|
|
// stored positions within the string.
|
|
|
|
LocalVariable* stack_;
|
|
|
|
LocalVariable* stack_pointer_;
|
|
|
|
|
|
|
|
// Stores the current character within the string.
|
|
|
|
LocalVariable* current_character_;
|
|
|
|
|
|
|
|
// Stores the current location within the string as a negative offset
|
|
|
|
// from the end of the string.
|
|
|
|
LocalVariable* current_position_;
|
|
|
|
|
|
|
|
// The string being processed, passed as a function parameter.
|
|
|
|
LocalVariable* string_param_;
|
|
|
|
|
|
|
|
// Stores the length of string_param_.
|
|
|
|
LocalVariable* string_param_length_;
|
|
|
|
|
|
|
|
// The start index within the string, passed as a function parameter.
|
|
|
|
LocalVariable* start_index_param_;
|
|
|
|
|
|
|
|
// An assortment of utility variables.
|
|
|
|
LocalVariable* capture_length_;
|
|
|
|
LocalVariable* match_start_index_;
|
|
|
|
LocalVariable* capture_start_index_;
|
|
|
|
LocalVariable* match_end_index_;
|
|
|
|
LocalVariable* char_in_capture_;
|
|
|
|
LocalVariable* char_in_match_;
|
|
|
|
LocalVariable* index_temp_;
|
|
|
|
|
|
|
|
LocalVariable* result_;
|
|
|
|
|
|
|
|
// Stored positions containing group bounds. Generated as needed.
|
|
|
|
LocalVariable* registers_;
|
|
|
|
intptr_t registers_count_;
|
|
|
|
const intptr_t saved_registers_count_;
|
|
|
|
|
|
|
|
// The actual array objects used for the stack and registers.
|
|
|
|
Array& stack_array_cell_;
|
|
|
|
TypedData& registers_array_;
|
|
|
|
|
|
|
|
IdAllocator block_id_;
|
|
|
|
IdAllocator temp_id_;
|
|
|
|
IdAllocator arg_id_;
|
|
|
|
IdAllocator local_id_;
|
|
|
|
IdAllocator indirect_id_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace dart
|
|
|
|
|
2016-10-26 07:26:03 +00:00
|
|
|
#endif // RUNTIME_VM_REGEXP_ASSEMBLER_IR_H_
|