2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/bc-pattern.h"
21 #include "hphp/runtime/vm/func.h"
24 //////////////////////////////////////////////////////////////////////
26 using Result
= BCPattern::Result
;
28 Result
BCPattern::matchAnchored(const Func
* func
) {
29 return matchAnchored(func
->unit()->entry() + func
->base(),
30 func
->unit()->entry() + func
->past());
33 Result
BCPattern::matchAnchored(PC start
, PC end
) {
36 matchAnchored(m_pattern
, start
, end
, result
);
40 void BCPattern::matchAnchored(const Expr
& pattern
,
41 PC start
, PC end
, Result
& result
) {
42 auto pos
= pattern
.begin();
44 for (auto inst
= start
; inst
!= end
; ) {
46 if (pos
== pattern
.end()) {
47 result
.m_start
= start
;
54 // Skip pattern-globally ignored opcodes.
55 if (m_ignores
.count(op
)) {
60 // Check for alternations whenever we fail to match.
62 if (!pos
->hasAlt()) return result
.erase();
64 // Pop the capture if we made one.
65 if (pos
->shouldCapture()) {
66 result
.m_captures
.pop_back();
69 for (auto const& atom
: pos
->getAlt()) {
70 // Construct the full alternate pattern.
71 auto alt
= Expr
{ atom
};
72 alt
.insert(alt
.end(), std::next(pos
), pattern
.end());
75 // Match on the alternate.
76 matchAnchored(alt
, inst
, end
, res
);
80 result
.m_start
= start
;
84 return result
.erase();
87 // Capture the atom if desired.
88 if (pos
->shouldCapture()) {
89 result
.m_captures
.push_back(inst
);
92 // Check for shallow match.
93 if (pos
->op() != op
) {
97 auto filter
= pos
->getFilter();
99 // Check for deep match if desired.
100 if (filter
&& !filter(inst
, result
.m_captures
)) {
104 if ((pos
->op() == Op::JmpZ
|| pos
->op() == Op::JmpNZ
)) {
105 // Match the taken block, if there is one.
106 auto off
= instrJumpOffset((Op
*)inst
);
110 matchAnchored(pos
->getTaken(), inst
+ *off
, end
, res
);
116 // Grab the captures.
117 result
.m_captures
= res
.m_captures
;
121 // Match the subsequence if we have one.
123 matchAnchored(pos
->getSeq(), next(inst
), end
, res
);
130 result
.m_captures
= res
.m_captures
;
141 // Detect a terminal match.
142 if (pos
== pattern
.end()) {
143 result
.m_start
= start
;
148 //////////////////////////////////////////////////////////////////////