Annotation of embedaddon/pcre/pcre_jit_compile.c, revision 1.1
1.1 ! misho 1: /*************************************************
! 2: * Perl-Compatible Regular Expressions *
! 3: *************************************************/
! 4:
! 5: /* PCRE is a library of functions to support regular expressions whose syntax
! 6: and semantics are as close as possible to those of the Perl 5 language.
! 7:
! 8: Written by Philip Hazel
! 9: Copyright (c) 1997-2008 University of Cambridge
! 10:
! 11: The machine code generator part (this module) was written by Zoltan Herczeg
! 12: Copyright (c) 2010-2011
! 13:
! 14: -----------------------------------------------------------------------------
! 15: Redistribution and use in source and binary forms, with or without
! 16: modification, are permitted provided that the following conditions are met:
! 17:
! 18: * Redistributions of source code must retain the above copyright notice,
! 19: this list of conditions and the following disclaimer.
! 20:
! 21: * Redistributions in binary form must reproduce the above copyright
! 22: notice, this list of conditions and the following disclaimer in the
! 23: documentation and/or other materials provided with the distribution.
! 24:
! 25: * Neither the name of the University of Cambridge nor the names of its
! 26: contributors may be used to endorse or promote products derived from
! 27: this software without specific prior written permission.
! 28:
! 29: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
! 30: AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 31: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 32: ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
! 33: LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 34: CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 35: SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 36: INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 37: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 38: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 39: POSSIBILITY OF SUCH DAMAGE.
! 40: -----------------------------------------------------------------------------
! 41: */
! 42:
! 43: #ifdef HAVE_CONFIG_H
! 44: #include "config.h"
! 45: #endif
! 46:
! 47: #include "pcre_internal.h"
! 48:
! 49: #ifdef SUPPORT_JIT
! 50:
! 51: /* All-in-one: Since we use the JIT compiler only from here,
! 52: we just include it. This way we don't need to touch the build
! 53: system files. */
! 54:
! 55: #define SLJIT_MALLOC(size) (pcre_malloc)(size)
! 56: #define SLJIT_FREE(ptr) (pcre_free)(ptr)
! 57: #define SLJIT_CONFIG_AUTO 1
! 58: #define SLJIT_CONFIG_STATIC 1
! 59: #define SLJIT_VERBOSE 0
! 60: #define SLJIT_DEBUG 0
! 61:
! 62: #include "sljit/sljitLir.c"
! 63:
! 64: #if defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED
! 65: #error "Unsupported architecture"
! 66: #endif
! 67:
! 68: /* Allocate memory on the stack. Fast, but limited size. */
! 69: #define LOCAL_SPACE_SIZE 32768
! 70:
! 71: #define STACK_GROWTH_RATE 8192
! 72:
! 73: /* Enable to check that the allocation could destroy temporaries. */
! 74: #if defined SLJIT_DEBUG && SLJIT_DEBUG
! 75: #define DESTROY_REGISTERS 1
! 76: #endif
! 77:
! 78: /*
! 79: Short summary about the backtracking mechanism empolyed by the jit code generator:
! 80:
! 81: The code generator follows the recursive nature of the PERL compatible regular
! 82: expressions. The basic blocks of regular expressions are condition checkers
! 83: whose execute different commands depending on the result of the condition check.
! 84: The relationship between the operators can be horizontal (concatenation) and
! 85: vertical (sub-expression) (See struct fallback_common for more details).
! 86:
! 87: 'ab' - 'a' and 'b' regexps are concatenated
! 88: 'a+' - 'a' is the sub-expression of the '+' operator
! 89:
! 90: The condition checkers are boolean (true/false) checkers. Machine code is generated
! 91: for the checker itself and for the actions depending on the result of the checker.
! 92: The 'true' case is called as the hot path (expected path), and the other is called as
! 93: the 'fallback' path. Branch instructions are expesive for all CPUs, so we avoid taken
! 94: branches on the hot path.
! 95:
! 96: Greedy star operator (*) :
! 97: Hot path: match happens.
! 98: Fallback path: match failed.
! 99: Non-greedy star operator (*?) :
! 100: Hot path: no need to perform a match.
! 101: Fallback path: match is required.
! 102:
! 103: The following example shows how the code generated for a capturing bracket
! 104: with two alternatives. Let A, B, C, D are arbirary regular expressions, and
! 105: we have the following regular expression:
! 106:
! 107: A(B|C)D
! 108:
! 109: The generated code will be the following:
! 110:
! 111: A hot path
! 112: '(' hot path (pushing arguments to the stack)
! 113: B hot path
! 114: ')' hot path (pushing arguments to the stack)
! 115: D hot path
! 116: return with successful match
! 117:
! 118: D fallback path
! 119: ')' fallback path (If we arrived from "C" jump to the fallback of "C")
! 120: B fallback path
! 121: C expected path
! 122: jump to D hot path
! 123: C fallback path
! 124: A fallback path
! 125:
! 126: Notice, that the order of fallback code paths are the opposite of the fast
! 127: code paths. In this way the topmost value on the stack is always belong
! 128: to the current fallback code path. The fallback code path must check
! 129: whether there is a next alternative. If so, it needs to jump back to
! 130: the hot path eventually. Otherwise it needs to clear out its own stack
! 131: frame and continue the execution on the fallback code paths.
! 132: */
! 133:
! 134: /*
! 135: Saved stack frames:
! 136:
! 137: Atomic blocks and asserts require reloading the values of local variables
! 138: when the fallback mechanism performed. Because of OP_RECURSE, the locals
! 139: are not necessarly known in compile time, thus we need a dynamic restore
! 140: mechanism.
! 141:
! 142: The stack frames are stored in a chain list, and have the following format:
! 143: ([ capturing bracket offset ][ start value ][ end value ])+ ... [ 0 ] [ previous head ]
! 144:
! 145: Thus we can restore the locals to a particular point in the stack.
! 146: */
! 147:
! 148: typedef struct jit_arguments {
! 149: /* Pointers first. */
! 150: struct sljit_stack *stack;
! 151: PCRE_SPTR str;
! 152: PCRE_SPTR begin;
! 153: PCRE_SPTR end;
! 154: int *offsets;
! 155: uschar *ptr;
! 156: /* Everything else after. */
! 157: int offsetcount;
! 158: int calllimit;
! 159: uschar notbol;
! 160: uschar noteol;
! 161: uschar notempty;
! 162: uschar notempty_atstart;
! 163: } jit_arguments;
! 164:
! 165: typedef struct executable_function {
! 166: void *executable_func;
! 167: pcre_jit_callback callback;
! 168: void *userdata;
! 169: sljit_uw executable_size;
! 170: } executable_function;
! 171:
! 172: typedef struct jump_list {
! 173: struct sljit_jump *jump;
! 174: struct jump_list *next;
! 175: } jump_list;
! 176:
! 177: enum stub_types { stack_alloc };
! 178:
! 179: typedef struct stub_list {
! 180: enum stub_types type;
! 181: int data;
! 182: struct sljit_jump *start;
! 183: struct sljit_label *leave;
! 184: struct stub_list *next;
! 185: } stub_list;
! 186:
! 187: typedef int (SLJIT_CALL *jit_function)(jit_arguments *args);
! 188:
! 189: /* The following structure is the key data type for the recursive
! 190: code generator. It is allocated by compile_hotpath, and contains
! 191: the aguments for compile_fallbackpath. Must be the first member
! 192: of its descendants. */
! 193: typedef struct fallback_common {
! 194: /* Concatenation stack. */
! 195: struct fallback_common *prev;
! 196: jump_list *nextfallbacks;
! 197: /* Internal stack (for component operators). */
! 198: struct fallback_common *top;
! 199: jump_list *topfallbacks;
! 200: /* Opcode pointer. */
! 201: uschar *cc;
! 202: } fallback_common;
! 203:
! 204: typedef struct assert_fallback {
! 205: fallback_common common;
! 206: jump_list *condfailed;
! 207: /* Less than 0 (-1) if a frame is not needed. */
! 208: int framesize;
! 209: /* Points to our private memory word on the stack. */
! 210: int localptr;
! 211: /* For iterators. */
! 212: struct sljit_label *hotpath;
! 213: } assert_fallback;
! 214:
! 215: typedef struct bracket_fallback {
! 216: fallback_common common;
! 217: /* Where to coninue if an alternative is successfully matched. */
! 218: struct sljit_label *althotpath;
! 219: /* For rmin and rmax iterators. */
! 220: struct sljit_label *recursivehotpath;
! 221: /* For greedy ? operator. */
! 222: struct sljit_label *zerohotpath;
! 223: /* Contains the branches of a failed condition. */
! 224: union {
! 225: /* Both for OP_COND, OP_SCOND. */
! 226: jump_list *condfailed;
! 227: assert_fallback *assert;
! 228: /* For OP_ONCE. -1 if not needed. */
! 229: int framesize;
! 230: } u;
! 231: /* Points to our private memory word on the stack. */
! 232: int localptr;
! 233: } bracket_fallback;
! 234:
! 235: typedef struct bracketpos_fallback {
! 236: fallback_common common;
! 237: /* Points to our private memory word on the stack. */
! 238: int localptr;
! 239: /* Reverting stack is needed. */
! 240: int framesize;
! 241: /* Allocated stack size. */
! 242: int stacksize;
! 243: } bracketpos_fallback;
! 244:
! 245: typedef struct braminzero_fallback {
! 246: fallback_common common;
! 247: struct sljit_label *hotpath;
! 248: } braminzero_fallback;
! 249:
! 250: typedef struct iterator_fallback {
! 251: fallback_common common;
! 252: /* Next iteration. */
! 253: struct sljit_label *hotpath;
! 254: } iterator_fallback;
! 255:
! 256: typedef struct recurse_entry {
! 257: struct recurse_entry *next;
! 258: /* Contains the function entry. */
! 259: struct sljit_label *entry;
! 260: /* Collects the calls until the function is not created. */
! 261: jump_list *calls;
! 262: /* Points to the starting opcode. */
! 263: int start;
! 264: } recurse_entry;
! 265:
! 266: typedef struct recurse_fallback {
! 267: fallback_common common;
! 268: } recurse_fallback;
! 269:
! 270: typedef struct compiler_common {
! 271: struct sljit_compiler *compiler;
! 272: uschar *start;
! 273: int localsize;
! 274: int *localptrs;
! 275: const uschar *fcc;
! 276: sljit_w lcc;
! 277: int cbraptr;
! 278: int nltype;
! 279: int newline;
! 280: int bsr_nltype;
! 281: int endonly;
! 282: sljit_w ctypes;
! 283: sljit_uw name_table;
! 284: sljit_w name_count;
! 285: sljit_w name_entry_size;
! 286: struct sljit_label *acceptlabel;
! 287: stub_list *stubs;
! 288: recurse_entry *entries;
! 289: recurse_entry *currententry;
! 290: jump_list *accept;
! 291: jump_list *calllimit;
! 292: jump_list *stackalloc;
! 293: jump_list *revertframes;
! 294: jump_list *wordboundary;
! 295: jump_list *anynewline;
! 296: jump_list *hspace;
! 297: jump_list *vspace;
! 298: jump_list *casefulcmp;
! 299: jump_list *caselesscmp;
! 300: BOOL jscript_compat;
! 301: #ifdef SUPPORT_UTF8
! 302: BOOL utf8;
! 303: #ifdef SUPPORT_UCP
! 304: BOOL useucp;
! 305: #endif
! 306: jump_list *utf8readchar;
! 307: jump_list *utf8readtype8;
! 308: #endif
! 309: #ifdef SUPPORT_UCP
! 310: jump_list *getucd;
! 311: #endif
! 312: } compiler_common;
! 313:
! 314: /* For byte_sequence_compare. */
! 315:
! 316: typedef struct compare_context {
! 317: int length;
! 318: int sourcereg;
! 319: #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
! 320: int byteptr;
! 321: union {
! 322: int asint;
! 323: short asshort;
! 324: sljit_ub asbyte;
! 325: sljit_ub asbytes[4];
! 326: } c;
! 327: union {
! 328: int asint;
! 329: short asshort;
! 330: sljit_ub asbyte;
! 331: sljit_ub asbytes[4];
! 332: } oc;
! 333: #endif
! 334: } compare_context;
! 335:
! 336: enum {
! 337: frame_end = 0,
! 338: frame_setstrbegin = -1
! 339: };
! 340:
! 341: /* Used for accessing the elements of the stack. */
! 342: #define STACK(i) ((-(i) - 1) * (int)sizeof(sljit_w))
! 343:
! 344: #define TMP1 SLJIT_TEMPORARY_REG1
! 345: #define TMP2 SLJIT_TEMPORARY_REG3
! 346: #define TMP3 SLJIT_TEMPORARY_EREG2
! 347: #define STR_PTR SLJIT_GENERAL_REG1
! 348: #define STR_END SLJIT_GENERAL_REG2
! 349: #define STACK_TOP SLJIT_TEMPORARY_REG2
! 350: #define STACK_LIMIT SLJIT_GENERAL_REG3
! 351: #define ARGUMENTS SLJIT_GENERAL_EREG1
! 352: #define CALL_COUNT SLJIT_GENERAL_EREG2
! 353: #define RETURN_ADDR SLJIT_TEMPORARY_EREG1
! 354:
! 355: /* Locals layout. */
! 356: /* These two locals can be used by the current opcode. */
! 357: #define LOCALS0 (0 * sizeof(sljit_w))
! 358: #define LOCALS1 (1 * sizeof(sljit_w))
! 359: /* Two local variables for possessive quantifiers (char1 cannot use them). */
! 360: #define POSSESSIVE0 (2 * sizeof(sljit_w))
! 361: #define POSSESSIVE1 (3 * sizeof(sljit_w))
! 362: /* Head of the last recursion. */
! 363: #define RECURSIVE_HEAD (4 * sizeof(sljit_w))
! 364: /* Max limit of recursions. */
! 365: #define CALL_LIMIT (5 * sizeof(sljit_w))
! 366: /* Last known position of the requested byte. */
! 367: #define REQ_BYTE_PTR (6 * sizeof(sljit_w))
! 368: /* End pointer of the first line. */
! 369: #define FIRSTLINE_END (7 * sizeof(sljit_w))
! 370: /* The output vector is stored on the stack, and contains pointers
! 371: to characters. The vector data is divided into two groups: the first
! 372: group contains the start / end character pointers, and the second is
! 373: the start pointers when the end of the capturing group has not yet reached. */
! 374: #define OVECTOR_START (8 * sizeof(sljit_w))
! 375: #define OVECTOR(i) (OVECTOR_START + (i) * sizeof(sljit_w))
! 376: #define OVECTOR_PRIV(i) (common->cbraptr + (i) * sizeof(sljit_w))
! 377: #define PRIV(cc) (common->localptrs[(cc) - common->start])
! 378:
! 379: /* Shortcuts. */
! 380: #define DEFINE_COMPILER \
! 381: struct sljit_compiler *compiler = common->compiler
! 382: #define OP1(op, dst, dstw, src, srcw) \
! 383: sljit_emit_op1(compiler, (op), (dst), (dstw), (src), (srcw))
! 384: #define OP2(op, dst, dstw, src1, src1w, src2, src2w) \
! 385: sljit_emit_op2(compiler, (op), (dst), (dstw), (src1), (src1w), (src2), (src2w))
! 386: #define LABEL() \
! 387: sljit_emit_label(compiler)
! 388: #define JUMP(type) \
! 389: sljit_emit_jump(compiler, (type))
! 390: #define JUMPTO(type, label) \
! 391: sljit_set_label(sljit_emit_jump(compiler, (type)), (label))
! 392: #define JUMPHERE(jump) \
! 393: sljit_set_label((jump), sljit_emit_label(compiler))
! 394: #define CMP(type, src1, src1w, src2, src2w) \
! 395: sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w))
! 396: #define CMPTO(type, src1, src1w, src2, src2w, label) \
! 397: sljit_set_label(sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)), (label))
! 398: #define COND_VALUE(op, dst, dstw, type) \
! 399: sljit_emit_cond_value(compiler, (op), (dst), (dstw), (type))
! 400:
! 401: static uschar* bracketend(uschar* cc)
! 402: {
! 403: SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND));
! 404: do cc += GET(cc, 1); while (*cc == OP_ALT);
! 405: SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS);
! 406: cc += 1 + LINK_SIZE;
! 407: return cc;
! 408: }
! 409:
! 410: /* Functions whose might need modification for all new supported opcodes:
! 411: next_opcode
! 412: get_localspace
! 413: set_localptrs
! 414: get_framesize
! 415: init_frame
! 416: get_localsize
! 417: copy_locals
! 418: compile_hotpath
! 419: compile_fallbackpath
! 420: */
! 421:
! 422: static uschar *next_opcode(compiler_common *common, uschar *cc)
! 423: {
! 424: SLJIT_UNUSED_ARG(common);
! 425: switch(*cc)
! 426: {
! 427: case OP_SOD:
! 428: case OP_SOM:
! 429: case OP_SET_SOM:
! 430: case OP_NOT_WORD_BOUNDARY:
! 431: case OP_WORD_BOUNDARY:
! 432: case OP_NOT_DIGIT:
! 433: case OP_DIGIT:
! 434: case OP_NOT_WHITESPACE:
! 435: case OP_WHITESPACE:
! 436: case OP_NOT_WORDCHAR:
! 437: case OP_WORDCHAR:
! 438: case OP_ANY:
! 439: case OP_ALLANY:
! 440: case OP_ANYNL:
! 441: case OP_NOT_HSPACE:
! 442: case OP_HSPACE:
! 443: case OP_NOT_VSPACE:
! 444: case OP_VSPACE:
! 445: case OP_EXTUNI:
! 446: case OP_EODN:
! 447: case OP_EOD:
! 448: case OP_CIRC:
! 449: case OP_CIRCM:
! 450: case OP_DOLL:
! 451: case OP_DOLLM:
! 452: case OP_TYPESTAR:
! 453: case OP_TYPEMINSTAR:
! 454: case OP_TYPEPLUS:
! 455: case OP_TYPEMINPLUS:
! 456: case OP_TYPEQUERY:
! 457: case OP_TYPEMINQUERY:
! 458: case OP_TYPEPOSSTAR:
! 459: case OP_TYPEPOSPLUS:
! 460: case OP_TYPEPOSQUERY:
! 461: case OP_CRSTAR:
! 462: case OP_CRMINSTAR:
! 463: case OP_CRPLUS:
! 464: case OP_CRMINPLUS:
! 465: case OP_CRQUERY:
! 466: case OP_CRMINQUERY:
! 467: case OP_DEF:
! 468: case OP_BRAZERO:
! 469: case OP_BRAMINZERO:
! 470: case OP_BRAPOSZERO:
! 471: case OP_FAIL:
! 472: case OP_ACCEPT:
! 473: case OP_ASSERT_ACCEPT:
! 474: case OP_SKIPZERO:
! 475: return cc + 1;
! 476:
! 477: case OP_ANYBYTE:
! 478: #ifdef SUPPORT_UTF8
! 479: if (common->utf8) return NULL;
! 480: #endif
! 481: return cc + 1;
! 482:
! 483: case OP_CHAR:
! 484: case OP_CHARI:
! 485: case OP_NOT:
! 486: case OP_NOTI:
! 487:
! 488: case OP_STAR:
! 489: case OP_MINSTAR:
! 490: case OP_PLUS:
! 491: case OP_MINPLUS:
! 492: case OP_QUERY:
! 493: case OP_MINQUERY:
! 494: case OP_POSSTAR:
! 495: case OP_POSPLUS:
! 496: case OP_POSQUERY:
! 497: case OP_STARI:
! 498: case OP_MINSTARI:
! 499: case OP_PLUSI:
! 500: case OP_MINPLUSI:
! 501: case OP_QUERYI:
! 502: case OP_MINQUERYI:
! 503: case OP_POSSTARI:
! 504: case OP_POSPLUSI:
! 505: case OP_POSQUERYI:
! 506: case OP_NOTSTAR:
! 507: case OP_NOTMINSTAR:
! 508: case OP_NOTPLUS:
! 509: case OP_NOTMINPLUS:
! 510: case OP_NOTQUERY:
! 511: case OP_NOTMINQUERY:
! 512: case OP_NOTPOSSTAR:
! 513: case OP_NOTPOSPLUS:
! 514: case OP_NOTPOSQUERY:
! 515: case OP_NOTSTARI:
! 516: case OP_NOTMINSTARI:
! 517: case OP_NOTPLUSI:
! 518: case OP_NOTMINPLUSI:
! 519: case OP_NOTQUERYI:
! 520: case OP_NOTMINQUERYI:
! 521: case OP_NOTPOSSTARI:
! 522: case OP_NOTPOSPLUSI:
! 523: case OP_NOTPOSQUERYI:
! 524: cc += 2;
! 525: #ifdef SUPPORT_UTF8
! 526: if (common->utf8 && cc[-1] >= 0xc0) cc += _pcre_utf8_table4[cc[-1] & 0x3f];
! 527: #endif
! 528: return cc;
! 529:
! 530: case OP_UPTO:
! 531: case OP_MINUPTO:
! 532: case OP_EXACT:
! 533: case OP_POSUPTO:
! 534: case OP_UPTOI:
! 535: case OP_MINUPTOI:
! 536: case OP_EXACTI:
! 537: case OP_POSUPTOI:
! 538: case OP_NOTUPTO:
! 539: case OP_NOTMINUPTO:
! 540: case OP_NOTEXACT:
! 541: case OP_NOTPOSUPTO:
! 542: case OP_NOTUPTOI:
! 543: case OP_NOTMINUPTOI:
! 544: case OP_NOTEXACTI:
! 545: case OP_NOTPOSUPTOI:
! 546: cc += 4;
! 547: #ifdef SUPPORT_UTF8
! 548: if (common->utf8 && cc[-1] >= 0xc0) cc += _pcre_utf8_table4[cc[-1] & 0x3f];
! 549: #endif
! 550: return cc;
! 551:
! 552: case OP_NOTPROP:
! 553: case OP_PROP:
! 554: case OP_TYPEUPTO:
! 555: case OP_TYPEMINUPTO:
! 556: case OP_TYPEEXACT:
! 557: case OP_TYPEPOSUPTO:
! 558: case OP_REF:
! 559: case OP_REFI:
! 560: case OP_CREF:
! 561: case OP_NCREF:
! 562: case OP_RREF:
! 563: case OP_NRREF:
! 564: case OP_CLOSE:
! 565: cc += 3;
! 566: return cc;
! 567:
! 568: case OP_CRRANGE:
! 569: case OP_CRMINRANGE:
! 570: return cc + 5;
! 571:
! 572: case OP_CLASS:
! 573: case OP_NCLASS:
! 574: return cc + 33;
! 575:
! 576: #ifdef SUPPORT_UTF8
! 577: case OP_XCLASS:
! 578: return cc + GET(cc, 1);
! 579: #endif
! 580:
! 581: case OP_RECURSE:
! 582: case OP_ASSERT:
! 583: case OP_ASSERT_NOT:
! 584: case OP_ASSERTBACK:
! 585: case OP_ASSERTBACK_NOT:
! 586: case OP_REVERSE:
! 587: case OP_ONCE:
! 588: case OP_ONCE_NC:
! 589: case OP_BRA:
! 590: case OP_BRAPOS:
! 591: case OP_COND:
! 592: case OP_SBRA:
! 593: case OP_SBRAPOS:
! 594: case OP_SCOND:
! 595: case OP_ALT:
! 596: case OP_KET:
! 597: case OP_KETRMAX:
! 598: case OP_KETRMIN:
! 599: case OP_KETRPOS:
! 600: return cc + 1 + LINK_SIZE;
! 601:
! 602: case OP_CBRA:
! 603: case OP_CBRAPOS:
! 604: case OP_SCBRA:
! 605: case OP_SCBRAPOS:
! 606: return cc + 1 + LINK_SIZE + 2;
! 607:
! 608: default:
! 609: return NULL;
! 610: }
! 611: }
! 612:
! 613: static int get_localspace(compiler_common *common, uschar *cc, uschar *ccend)
! 614: {
! 615: int localspace = 0;
! 616: uschar *alternative;
! 617: /* Calculate important variables (like stack size) and checks whether all opcodes are supported. */
! 618: while (cc < ccend)
! 619: {
! 620: switch(*cc)
! 621: {
! 622: case OP_ASSERT:
! 623: case OP_ASSERT_NOT:
! 624: case OP_ASSERTBACK:
! 625: case OP_ASSERTBACK_NOT:
! 626: case OP_ONCE:
! 627: case OP_ONCE_NC:
! 628: case OP_BRAPOS:
! 629: case OP_SBRA:
! 630: case OP_SBRAPOS:
! 631: case OP_SCOND:
! 632: localspace += sizeof(sljit_w);
! 633: cc += 1 + LINK_SIZE;
! 634: break;
! 635:
! 636: case OP_CBRAPOS:
! 637: case OP_SCBRAPOS:
! 638: localspace += sizeof(sljit_w);
! 639: cc += 1 + LINK_SIZE + 2;
! 640: break;
! 641:
! 642: case OP_COND:
! 643: /* Might be a hidden SCOND. */
! 644: alternative = cc + GET(cc, 1);
! 645: if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
! 646: localspace += sizeof(sljit_w);
! 647: cc += 1 + LINK_SIZE;
! 648: break;
! 649:
! 650: default:
! 651: cc = next_opcode(common, cc);
! 652: if (cc == NULL)
! 653: return -1;
! 654: break;
! 655: }
! 656: }
! 657: return localspace;
! 658: }
! 659:
! 660: static void set_localptrs(compiler_common *common, int localptr, uschar *ccend)
! 661: {
! 662: uschar *cc = common->start;
! 663: uschar *alternative;
! 664: while (cc < ccend)
! 665: {
! 666: switch(*cc)
! 667: {
! 668: case OP_ASSERT:
! 669: case OP_ASSERT_NOT:
! 670: case OP_ASSERTBACK:
! 671: case OP_ASSERTBACK_NOT:
! 672: case OP_ONCE:
! 673: case OP_ONCE_NC:
! 674: case OP_BRAPOS:
! 675: case OP_SBRA:
! 676: case OP_SBRAPOS:
! 677: case OP_SCOND:
! 678: common->localptrs[cc - common->start] = localptr;
! 679: localptr += sizeof(sljit_w);
! 680: cc += 1 + LINK_SIZE;
! 681: break;
! 682:
! 683: case OP_CBRAPOS:
! 684: case OP_SCBRAPOS:
! 685: common->localptrs[cc - common->start] = localptr;
! 686: localptr += sizeof(sljit_w);
! 687: cc += 1 + LINK_SIZE + 2;
! 688: break;
! 689:
! 690: case OP_COND:
! 691: /* Might be a hidden SCOND. */
! 692: alternative = cc + GET(cc, 1);
! 693: if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
! 694: {
! 695: common->localptrs[cc - common->start] = localptr;
! 696: localptr += sizeof(sljit_w);
! 697: }
! 698: cc += 1 + LINK_SIZE;
! 699: break;
! 700:
! 701: default:
! 702: cc = next_opcode(common, cc);
! 703: SLJIT_ASSERT(cc != NULL);
! 704: break;
! 705: }
! 706: }
! 707: }
! 708:
! 709: /* Returns with -1 if no need for frame. */
! 710: static int get_framesize(compiler_common *common, uschar *cc, BOOL recursive)
! 711: {
! 712: uschar *ccend = bracketend(cc);
! 713: int length = 0;
! 714: BOOL possessive = FALSE;
! 715: BOOL setsom_found = FALSE;
! 716:
! 717: if (!recursive && (*cc == OP_CBRAPOS || *cc == OP_SCBRAPOS))
! 718: {
! 719: length = 3;
! 720: possessive = TRUE;
! 721: }
! 722:
! 723: cc = next_opcode(common, cc);
! 724: SLJIT_ASSERT(cc != NULL);
! 725: while (cc < ccend)
! 726: switch(*cc)
! 727: {
! 728: case OP_SET_SOM:
! 729: case OP_RECURSE:
! 730: if (!setsom_found)
! 731: {
! 732: length += 2;
! 733: setsom_found = TRUE;
! 734: }
! 735: cc += (*cc == OP_SET_SOM) ? 1 : 1 + LINK_SIZE;
! 736: break;
! 737:
! 738: case OP_CBRA:
! 739: case OP_CBRAPOS:
! 740: case OP_SCBRA:
! 741: case OP_SCBRAPOS:
! 742: length += 3;
! 743: cc += 1 + LINK_SIZE + 2;
! 744: break;
! 745:
! 746: default:
! 747: cc = next_opcode(common, cc);
! 748: SLJIT_ASSERT(cc != NULL);
! 749: break;
! 750: }
! 751:
! 752: /* Possessive quantifiers can use a special case. */
! 753: if (SLJIT_UNLIKELY(possessive) && length == 3)
! 754: return -1;
! 755:
! 756: if (length > 0)
! 757: return length + 1;
! 758: return -1;
! 759: }
! 760:
! 761: static void init_frame(compiler_common *common, uschar *cc, int stackpos, int stacktop, BOOL recursive)
! 762: {
! 763: DEFINE_COMPILER;
! 764: uschar *ccend = bracketend(cc);
! 765: BOOL setsom_found = FALSE;
! 766: int offset;
! 767:
! 768: /* >= 1 + shortest item size (2) */
! 769: SLJIT_ASSERT(stackpos >= stacktop + 2);
! 770:
! 771: stackpos = STACK(stackpos);
! 772: if (recursive || (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS))
! 773: cc = next_opcode(common, cc);
! 774: SLJIT_ASSERT(cc != NULL);
! 775: while (cc < ccend)
! 776: switch(*cc)
! 777: {
! 778: case OP_SET_SOM:
! 779: case OP_RECURSE:
! 780: if (!setsom_found)
! 781: {
! 782: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0));
! 783: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, frame_setstrbegin);
! 784: stackpos += (int)sizeof(sljit_w);
! 785: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
! 786: stackpos += (int)sizeof(sljit_w);
! 787: setsom_found = TRUE;
! 788: }
! 789: cc += (*cc == OP_SET_SOM) ? 1 : 1 + LINK_SIZE;
! 790: break;
! 791:
! 792: case OP_CBRA:
! 793: case OP_CBRAPOS:
! 794: case OP_SCBRA:
! 795: case OP_SCBRAPOS:
! 796: offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
! 797: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset));
! 798: stackpos += (int)sizeof(sljit_w);
! 799: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset));
! 800: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1));
! 801: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
! 802: stackpos += (int)sizeof(sljit_w);
! 803: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0);
! 804: stackpos += (int)sizeof(sljit_w);
! 805:
! 806: cc += 1 + LINK_SIZE + 2;
! 807: break;
! 808:
! 809: default:
! 810: cc = next_opcode(common, cc);
! 811: SLJIT_ASSERT(cc != NULL);
! 812: break;
! 813: }
! 814:
! 815: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, frame_end);
! 816: SLJIT_ASSERT(stackpos == STACK(stacktop));
! 817: }
! 818:
! 819: static SLJIT_INLINE int get_localsize(compiler_common *common, uschar *cc, uschar *ccend)
! 820: {
! 821: int localsize = 2;
! 822: uschar *alternative;
! 823: /* Calculate the sum of the local variables. */
! 824: while (cc < ccend)
! 825: {
! 826: switch(*cc)
! 827: {
! 828: case OP_ASSERT:
! 829: case OP_ASSERT_NOT:
! 830: case OP_ASSERTBACK:
! 831: case OP_ASSERTBACK_NOT:
! 832: case OP_ONCE:
! 833: case OP_ONCE_NC:
! 834: case OP_BRAPOS:
! 835: case OP_SBRA:
! 836: case OP_SBRAPOS:
! 837: case OP_SCOND:
! 838: localsize++;
! 839: cc += 1 + LINK_SIZE;
! 840: break;
! 841:
! 842: case OP_CBRA:
! 843: case OP_SCBRA:
! 844: localsize++;
! 845: cc += 1 + LINK_SIZE + 2;
! 846: break;
! 847:
! 848: case OP_CBRAPOS:
! 849: case OP_SCBRAPOS:
! 850: localsize += 2;
! 851: cc += 1 + LINK_SIZE + 2;
! 852: break;
! 853:
! 854: case OP_COND:
! 855: /* Might be a hidden SCOND. */
! 856: alternative = cc + GET(cc, 1);
! 857: if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
! 858: localsize++;
! 859: cc += 1 + LINK_SIZE;
! 860: break;
! 861:
! 862: default:
! 863: cc = next_opcode(common, cc);
! 864: SLJIT_ASSERT(cc != NULL);
! 865: break;
! 866: }
! 867: }
! 868: SLJIT_ASSERT(cc == ccend);
! 869: return localsize;
! 870: }
! 871:
! 872: static void copy_locals(compiler_common *common, uschar *cc, uschar *ccend,
! 873: BOOL save, int stackptr, int stacktop)
! 874: {
! 875: DEFINE_COMPILER;
! 876: int srcw[2];
! 877: int count;
! 878: BOOL tmp1next = TRUE;
! 879: BOOL tmp1empty = TRUE;
! 880: BOOL tmp2empty = TRUE;
! 881: uschar *alternative;
! 882: enum {
! 883: start,
! 884: loop,
! 885: end
! 886: } status;
! 887:
! 888: status = save ? start : loop;
! 889: stackptr = STACK(stackptr - 2);
! 890: stacktop = STACK(stacktop - 1);
! 891:
! 892: if (!save)
! 893: {
! 894: stackptr += sizeof(sljit_w);
! 895: if (stackptr < stacktop)
! 896: {
! 897: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), stackptr);
! 898: stackptr += sizeof(sljit_w);
! 899: tmp1empty = FALSE;
! 900: }
! 901: if (stackptr < stacktop)
! 902: {
! 903: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), stackptr);
! 904: stackptr += sizeof(sljit_w);
! 905: tmp2empty = FALSE;
! 906: }
! 907: /* The tmp1next must be TRUE in either way. */
! 908: }
! 909:
! 910: while (status != end)
! 911: {
! 912: count = 0;
! 913: switch(status)
! 914: {
! 915: case start:
! 916: SLJIT_ASSERT(save);
! 917: count = 1;
! 918: srcw[0] = RECURSIVE_HEAD;
! 919: status = loop;
! 920: break;
! 921:
! 922: case loop:
! 923: if (cc >= ccend)
! 924: {
! 925: status = end;
! 926: break;
! 927: }
! 928:
! 929: switch(*cc)
! 930: {
! 931: case OP_ASSERT:
! 932: case OP_ASSERT_NOT:
! 933: case OP_ASSERTBACK:
! 934: case OP_ASSERTBACK_NOT:
! 935: case OP_ONCE:
! 936: case OP_ONCE_NC:
! 937: case OP_BRAPOS:
! 938: case OP_SBRA:
! 939: case OP_SBRAPOS:
! 940: case OP_SCOND:
! 941: count = 1;
! 942: srcw[0] = PRIV(cc);
! 943: SLJIT_ASSERT(srcw[0] != 0);
! 944: cc += 1 + LINK_SIZE;
! 945: break;
! 946:
! 947: case OP_CBRA:
! 948: case OP_SCBRA:
! 949: count = 1;
! 950: srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
! 951: cc += 1 + LINK_SIZE + 2;
! 952: break;
! 953:
! 954: case OP_CBRAPOS:
! 955: case OP_SCBRAPOS:
! 956: count = 2;
! 957: srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
! 958: srcw[0] = PRIV(cc);
! 959: SLJIT_ASSERT(srcw[0] != 0);
! 960: cc += 1 + LINK_SIZE + 2;
! 961: break;
! 962:
! 963: case OP_COND:
! 964: /* Might be a hidden SCOND. */
! 965: alternative = cc + GET(cc, 1);
! 966: if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
! 967: {
! 968: count = 1;
! 969: srcw[0] = PRIV(cc);
! 970: SLJIT_ASSERT(srcw[0] != 0);
! 971: }
! 972: cc += 1 + LINK_SIZE;
! 973: break;
! 974:
! 975: default:
! 976: cc = next_opcode(common, cc);
! 977: SLJIT_ASSERT(cc != NULL);
! 978: break;
! 979: }
! 980: break;
! 981:
! 982: case end:
! 983: SLJIT_ASSERT_STOP();
! 984: break;
! 985: }
! 986:
! 987: while (count > 0)
! 988: {
! 989: count--;
! 990: if (save)
! 991: {
! 992: if (tmp1next)
! 993: {
! 994: if (!tmp1empty)
! 995: {
! 996: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0);
! 997: stackptr += sizeof(sljit_w);
! 998: }
! 999: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), srcw[count]);
! 1000: tmp1empty = FALSE;
! 1001: tmp1next = FALSE;
! 1002: }
! 1003: else
! 1004: {
! 1005: if (!tmp2empty)
! 1006: {
! 1007: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0);
! 1008: stackptr += sizeof(sljit_w);
! 1009: }
! 1010: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), srcw[count]);
! 1011: tmp2empty = FALSE;
! 1012: tmp1next = TRUE;
! 1013: }
! 1014: }
! 1015: else
! 1016: {
! 1017: if (tmp1next)
! 1018: {
! 1019: SLJIT_ASSERT(!tmp1empty);
! 1020: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), srcw[count], TMP1, 0);
! 1021: tmp1empty = stackptr >= stacktop;
! 1022: if (!tmp1empty)
! 1023: {
! 1024: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), stackptr);
! 1025: stackptr += sizeof(sljit_w);
! 1026: }
! 1027: tmp1next = FALSE;
! 1028: }
! 1029: else
! 1030: {
! 1031: SLJIT_ASSERT(!tmp2empty);
! 1032: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), srcw[count], TMP2, 0);
! 1033: tmp2empty = stackptr >= stacktop;
! 1034: if (!tmp2empty)
! 1035: {
! 1036: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), stackptr);
! 1037: stackptr += sizeof(sljit_w);
! 1038: }
! 1039: tmp1next = TRUE;
! 1040: }
! 1041: }
! 1042: }
! 1043: }
! 1044:
! 1045: if (save)
! 1046: {
! 1047: if (tmp1next)
! 1048: {
! 1049: if (!tmp1empty)
! 1050: {
! 1051: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0);
! 1052: stackptr += sizeof(sljit_w);
! 1053: }
! 1054: if (!tmp2empty)
! 1055: {
! 1056: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0);
! 1057: stackptr += sizeof(sljit_w);
! 1058: }
! 1059: }
! 1060: else
! 1061: {
! 1062: if (!tmp2empty)
! 1063: {
! 1064: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0);
! 1065: stackptr += sizeof(sljit_w);
! 1066: }
! 1067: if (!tmp1empty)
! 1068: {
! 1069: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0);
! 1070: stackptr += sizeof(sljit_w);
! 1071: }
! 1072: }
! 1073: }
! 1074: SLJIT_ASSERT(cc == ccend && stackptr == stacktop && (save || (tmp1empty && tmp2empty)));
! 1075: }
! 1076:
! 1077: static SLJIT_INLINE BOOL ispowerof2(unsigned int value)
! 1078: {
! 1079: return (value & (value - 1)) == 0;
! 1080: }
! 1081:
! 1082: static SLJIT_INLINE void set_jumps(jump_list *list, struct sljit_label *label)
! 1083: {
! 1084: while (list)
! 1085: {
! 1086: /* sljit_set_label is clever enough to do nothing
! 1087: if either the jump or the label is NULL */
! 1088: sljit_set_label(list->jump, label);
! 1089: list = list->next;
! 1090: }
! 1091: }
! 1092:
! 1093: static SLJIT_INLINE void add_jump(struct sljit_compiler *compiler, jump_list **list, struct sljit_jump* jump)
! 1094: {
! 1095: jump_list *list_item = sljit_alloc_memory(compiler, sizeof(jump_list));
! 1096: if (list_item)
! 1097: {
! 1098: list_item->next = *list;
! 1099: list_item->jump = jump;
! 1100: *list = list_item;
! 1101: }
! 1102: }
! 1103:
! 1104: static void add_stub(compiler_common *common, enum stub_types type, int data, struct sljit_jump *start)
! 1105: {
! 1106: DEFINE_COMPILER;
! 1107: stub_list* list_item = sljit_alloc_memory(compiler, sizeof(stub_list));
! 1108:
! 1109: if (list_item)
! 1110: {
! 1111: list_item->type = type;
! 1112: list_item->data = data;
! 1113: list_item->start = start;
! 1114: list_item->leave = LABEL();
! 1115: list_item->next = common->stubs;
! 1116: common->stubs = list_item;
! 1117: }
! 1118: }
! 1119:
! 1120: static void flush_stubs(compiler_common *common)
! 1121: {
! 1122: DEFINE_COMPILER;
! 1123: stub_list* list_item = common->stubs;
! 1124:
! 1125: while (list_item)
! 1126: {
! 1127: JUMPHERE(list_item->start);
! 1128: switch(list_item->type)
! 1129: {
! 1130: case stack_alloc:
! 1131: add_jump(compiler, &common->stackalloc, JUMP(SLJIT_FAST_CALL));
! 1132: break;
! 1133: }
! 1134: JUMPTO(SLJIT_JUMP, list_item->leave);
! 1135: list_item = list_item->next;
! 1136: }
! 1137: common->stubs = NULL;
! 1138: }
! 1139:
! 1140: static SLJIT_INLINE void decrease_call_count(compiler_common *common)
! 1141: {
! 1142: DEFINE_COMPILER;
! 1143:
! 1144: OP2(SLJIT_SUB | SLJIT_SET_E, CALL_COUNT, 0, CALL_COUNT, 0, SLJIT_IMM, 1);
! 1145: add_jump(compiler, &common->calllimit, JUMP(SLJIT_C_ZERO));
! 1146: }
! 1147:
! 1148: static SLJIT_INLINE void allocate_stack(compiler_common *common, int size)
! 1149: {
! 1150: /* May destroy all locals and registers except TMP2. */
! 1151: DEFINE_COMPILER;
! 1152:
! 1153: OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_w));
! 1154: #ifdef DESTROY_REGISTERS
! 1155: OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345);
! 1156: OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
! 1157: OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
! 1158: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, TMP1, 0);
! 1159: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, TMP1, 0);
! 1160: #endif
! 1161: add_stub(common, stack_alloc, 0, CMP(SLJIT_C_GREATER, STACK_TOP, 0, STACK_LIMIT, 0));
! 1162: }
! 1163:
! 1164: static SLJIT_INLINE void free_stack(compiler_common *common, int size)
! 1165: {
! 1166: DEFINE_COMPILER;
! 1167: OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_w));
! 1168: }
! 1169:
! 1170: static SLJIT_INLINE void reset_ovector(compiler_common *common, int length)
! 1171: {
! 1172: DEFINE_COMPILER;
! 1173: struct sljit_label *loop;
! 1174: int i;
! 1175: /* At this point we can freely use all temporary registers. */
! 1176: /* TMP1 returns with begin - 1. */
! 1177: OP2(SLJIT_SUB, SLJIT_TEMPORARY_REG1, 0, SLJIT_MEM1(SLJIT_GENERAL_REG1), SLJIT_OFFSETOF(jit_arguments, begin), SLJIT_IMM, 1);
! 1178: if (length < 8)
! 1179: {
! 1180: for (i = 0; i < length; i++)
! 1181: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(i), SLJIT_TEMPORARY_REG1, 0);
! 1182: }
! 1183: else
! 1184: {
! 1185: OP2(SLJIT_ADD, SLJIT_TEMPORARY_REG2, 0, SLJIT_LOCALS_REG, 0, SLJIT_IMM, OVECTOR_START - sizeof(sljit_w));
! 1186: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, length);
! 1187: loop = LABEL();
! 1188: OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), sizeof(sljit_w), SLJIT_TEMPORARY_REG1, 0);
! 1189: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_TEMPORARY_REG3, 0, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, 1);
! 1190: JUMPTO(SLJIT_C_NOT_ZERO, loop);
! 1191: }
! 1192: }
! 1193:
! 1194: static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket)
! 1195: {
! 1196: DEFINE_COMPILER;
! 1197: struct sljit_label *loop;
! 1198: struct sljit_jump *earlyexit;
! 1199:
! 1200: /* At this point we can freely use all registers. */
! 1201: OP1(SLJIT_MOV, SLJIT_GENERAL_REG3, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1));
! 1202: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1), STR_PTR, 0);
! 1203:
! 1204: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG1, 0, ARGUMENTS, 0);
! 1205: OP1(SLJIT_MOV_SI, SLJIT_TEMPORARY_REG2, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG1), SLJIT_OFFSETOF(jit_arguments, offsetcount));
! 1206: OP2(SLJIT_SUB, SLJIT_TEMPORARY_REG3, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG1), SLJIT_OFFSETOF(jit_arguments, offsets), SLJIT_IMM, sizeof(int));
! 1207: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG1, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG1), SLJIT_OFFSETOF(jit_arguments, begin));
! 1208: OP2(SLJIT_ADD, SLJIT_GENERAL_REG1, 0, SLJIT_LOCALS_REG, 0, SLJIT_IMM, OVECTOR_START);
! 1209: /* Unlikely, but possible */
! 1210: earlyexit = CMP(SLJIT_C_EQUAL, SLJIT_TEMPORARY_REG2, 0, SLJIT_IMM, 0);
! 1211: loop = LABEL();
! 1212: OP2(SLJIT_SUB, SLJIT_GENERAL_REG2, 0, SLJIT_MEM1(SLJIT_GENERAL_REG1), 0, SLJIT_TEMPORARY_REG1, 0);
! 1213: OP2(SLJIT_ADD, SLJIT_GENERAL_REG1, 0, SLJIT_GENERAL_REG1, 0, SLJIT_IMM, sizeof(sljit_w));
! 1214: /* Copy the integer value to the output buffer */
! 1215: OP1(SLJIT_MOVU_SI, SLJIT_MEM1(SLJIT_TEMPORARY_REG3), sizeof(int), SLJIT_GENERAL_REG2, 0);
! 1216: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_TEMPORARY_REG2, 0, SLJIT_TEMPORARY_REG2, 0, SLJIT_IMM, 1);
! 1217: JUMPTO(SLJIT_C_NOT_ZERO, loop);
! 1218: JUMPHERE(earlyexit);
! 1219:
! 1220: /* Calculate the return value, which is the maximum ovector value. */
! 1221: if (topbracket > 1)
! 1222: {
! 1223: OP2(SLJIT_ADD, SLJIT_TEMPORARY_REG1, 0, SLJIT_LOCALS_REG, 0, SLJIT_IMM, OVECTOR_START + topbracket * 2 * sizeof(sljit_w));
! 1224: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG2, 0, SLJIT_IMM, topbracket + 1);
! 1225:
! 1226: /* OVECTOR(0) is never equal to SLJIT_GENERAL_REG3. */
! 1227: loop = LABEL();
! 1228: OP1(SLJIT_MOVU, SLJIT_TEMPORARY_REG3, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG1), -(2 * (sljit_w)sizeof(sljit_w)));
! 1229: OP2(SLJIT_SUB, SLJIT_TEMPORARY_REG2, 0, SLJIT_TEMPORARY_REG2, 0, SLJIT_IMM, 1);
! 1230: CMPTO(SLJIT_C_EQUAL, SLJIT_TEMPORARY_REG3, 0, SLJIT_GENERAL_REG3, 0, loop);
! 1231: OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_TEMPORARY_REG2, 0);
! 1232: }
! 1233: else
! 1234: OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1);
! 1235: }
! 1236:
! 1237: static SLJIT_INLINE BOOL char_has_othercase(compiler_common *common, uschar* cc)
! 1238: {
! 1239: /* Detects if the character has an othercase. */
! 1240: unsigned int c;
! 1241:
! 1242: #ifdef SUPPORT_UTF8
! 1243: if (common->utf8)
! 1244: {
! 1245: GETCHAR(c, cc);
! 1246: if (c > 127)
! 1247: {
! 1248: #ifdef SUPPORT_UCP
! 1249: return c != UCD_OTHERCASE(c);
! 1250: #else
! 1251: return FALSE;
! 1252: #endif
! 1253: }
! 1254: }
! 1255: else
! 1256: #endif
! 1257: c = *cc;
! 1258: return common->fcc[c] != c;
! 1259: }
! 1260:
! 1261: static SLJIT_INLINE unsigned int char_othercase(compiler_common *common, unsigned int c)
! 1262: {
! 1263: /* Returns with the othercase. */
! 1264: #ifdef SUPPORT_UTF8
! 1265: if (common->utf8 && c > 127)
! 1266: {
! 1267: #ifdef SUPPORT_UCP
! 1268: return UCD_OTHERCASE(c);
! 1269: #else
! 1270: return c;
! 1271: #endif
! 1272: }
! 1273: #endif
! 1274: return common->fcc[c];
! 1275: }
! 1276:
! 1277: static unsigned int char_get_othercase_bit(compiler_common *common, uschar* cc)
! 1278: {
! 1279: /* Detects if the character and its othercase has only 1 bit difference. */
! 1280: unsigned int c, oc, bit;
! 1281: #ifdef SUPPORT_UTF8
! 1282: int n;
! 1283: #endif
! 1284:
! 1285: #ifdef SUPPORT_UTF8
! 1286: if (common->utf8)
! 1287: {
! 1288: GETCHAR(c, cc);
! 1289: if (c <= 127)
! 1290: oc = common->fcc[c];
! 1291: else
! 1292: {
! 1293: #ifdef SUPPORT_UCP
! 1294: oc = UCD_OTHERCASE(c);
! 1295: #else
! 1296: oc = c;
! 1297: #endif
! 1298: }
! 1299: }
! 1300: else
! 1301: {
! 1302: c = *cc;
! 1303: oc = common->fcc[c];
! 1304: }
! 1305: #else
! 1306: c = *cc;
! 1307: oc = common->fcc[c];
! 1308: #endif
! 1309:
! 1310: SLJIT_ASSERT(c != oc);
! 1311:
! 1312: bit = c ^ oc;
! 1313: /* Optimized for English alphabet. */
! 1314: if (c <= 127 && bit == 0x20)
! 1315: return (0 << 8) | 0x20;
! 1316:
! 1317: /* Since c != oc, they must have at least 1 bit difference. */
! 1318: if (!ispowerof2(bit))
! 1319: return 0;
! 1320:
! 1321: #ifdef SUPPORT_UTF8
! 1322: if (common->utf8 && c > 127)
! 1323: {
! 1324: n = _pcre_utf8_table4[*cc & 0x3f];
! 1325: while ((bit & 0x3f) == 0)
! 1326: {
! 1327: n--;
! 1328: bit >>= 6;
! 1329: }
! 1330: return (n << 8) | bit;
! 1331: }
! 1332: #endif
! 1333: return (0 << 8) | bit;
! 1334: }
! 1335:
! 1336: static SLJIT_INLINE void check_input_end(compiler_common *common, jump_list **fallbacks)
! 1337: {
! 1338: DEFINE_COMPILER;
! 1339: add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
! 1340: }
! 1341:
! 1342: static void read_char(compiler_common *common)
! 1343: {
! 1344: /* Reads the character into TMP1, updates STR_PTR.
! 1345: Does not check STR_END. TMP2 Destroyed. */
! 1346: DEFINE_COMPILER;
! 1347: #ifdef SUPPORT_UTF8
! 1348: struct sljit_jump *jump;
! 1349: #endif
! 1350:
! 1351: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1352: #ifdef SUPPORT_UTF8
! 1353: if (common->utf8)
! 1354: {
! 1355: jump = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
! 1356: add_jump(compiler, &common->utf8readchar, JUMP(SLJIT_FAST_CALL));
! 1357: JUMPHERE(jump);
! 1358: }
! 1359: #endif
! 1360: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1361: }
! 1362:
! 1363: static void peek_char(compiler_common *common)
! 1364: {
! 1365: /* Reads the character into TMP1, keeps STR_PTR.
! 1366: Does not check STR_END. TMP2 Destroyed. */
! 1367: DEFINE_COMPILER;
! 1368: #ifdef SUPPORT_UTF8
! 1369: struct sljit_jump *jump;
! 1370: #endif
! 1371:
! 1372: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1373: #ifdef SUPPORT_UTF8
! 1374: if (common->utf8)
! 1375: {
! 1376: jump = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
! 1377: add_jump(compiler, &common->utf8readchar, JUMP(SLJIT_FAST_CALL));
! 1378: OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
! 1379: JUMPHERE(jump);
! 1380: }
! 1381: #endif
! 1382: }
! 1383:
! 1384: static void read_char8_type(compiler_common *common)
! 1385: {
! 1386: /* Reads the character type into TMP1, updates STR_PTR. Does not check STR_END. */
! 1387: DEFINE_COMPILER;
! 1388: #ifdef SUPPORT_UTF8
! 1389: struct sljit_jump *jump;
! 1390: #endif
! 1391:
! 1392: #ifdef SUPPORT_UTF8
! 1393: if (common->utf8)
! 1394: {
! 1395: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 0);
! 1396: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1397: /* This can be an extra read in some situations, but hopefully
! 1398: it is a clever early read in most cases. */
! 1399: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
! 1400: jump = CMP(SLJIT_C_LESS, TMP2, 0, SLJIT_IMM, 0xc0);
! 1401: add_jump(compiler, &common->utf8readtype8, JUMP(SLJIT_FAST_CALL));
! 1402: JUMPHERE(jump);
! 1403: return;
! 1404: }
! 1405: #endif
! 1406: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1407: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1408: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), common->ctypes);
! 1409: }
! 1410:
! 1411: static void skip_char_back(compiler_common *common)
! 1412: {
! 1413: /* Goes one character back. Only affects STR_PTR. Does not check begin. */
! 1414: DEFINE_COMPILER;
! 1415: #ifdef SUPPORT_UTF8
! 1416: struct sljit_label *label;
! 1417:
! 1418: if (common->utf8)
! 1419: {
! 1420: label = LABEL();
! 1421: OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1422: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1423: OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
! 1424: CMPTO(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, label);
! 1425: return;
! 1426: }
! 1427: #endif
! 1428: OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1429: }
! 1430:
! 1431: static void check_newlinechar(compiler_common *common, int nltype, jump_list **fallbacks, BOOL jumpiftrue)
! 1432: {
! 1433: /* Character comes in TMP1. Checks if it is a newline. TMP2 may be destroyed. */
! 1434: DEFINE_COMPILER;
! 1435:
! 1436: if (nltype == NLTYPE_ANY)
! 1437: {
! 1438: add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL));
! 1439: add_jump(compiler, fallbacks, JUMP(jumpiftrue ? SLJIT_C_NOT_ZERO : SLJIT_C_ZERO));
! 1440: }
! 1441: else if (nltype == NLTYPE_ANYCRLF)
! 1442: {
! 1443: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_CR);
! 1444: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL);
! 1445: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL);
! 1446: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 1447: add_jump(compiler, fallbacks, JUMP(jumpiftrue ? SLJIT_C_NOT_ZERO : SLJIT_C_ZERO));
! 1448: }
! 1449: else
! 1450: {
! 1451: SLJIT_ASSERT(nltype == NLTYPE_FIXED && common->newline <= 255);
! 1452: add_jump(compiler, fallbacks, CMP(jumpiftrue ? SLJIT_C_EQUAL : SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline));
! 1453: }
! 1454: }
! 1455:
! 1456: #ifdef SUPPORT_UTF8
! 1457: static void do_utf8readchar(compiler_common *common)
! 1458: {
! 1459: /* Fast decoding an utf8 character. TMP1 contains the first byte
! 1460: of the character (>= 0xc0). Return char value in TMP1, length - 1 in TMP2. */
! 1461: DEFINE_COMPILER;
! 1462: struct sljit_jump *jump;
! 1463:
! 1464: sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
! 1465: /* Searching for the first zero. */
! 1466: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20);
! 1467: jump = JUMP(SLJIT_C_NOT_ZERO);
! 1468: /* 2 byte sequence */
! 1469: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 1);
! 1470: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1471: OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1f);
! 1472: OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
! 1473: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1474: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1475: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
! 1476: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 1477: JUMPHERE(jump);
! 1478:
! 1479: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x10);
! 1480: jump = JUMP(SLJIT_C_NOT_ZERO);
! 1481: /* 3 byte sequence */
! 1482: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 1);
! 1483: OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0f);
! 1484: OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 12);
! 1485: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1486: OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
! 1487: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1488: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 2);
! 1489: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 2);
! 1490: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1491: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1492: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 2);
! 1493: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 1494: JUMPHERE(jump);
! 1495:
! 1496: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x08);
! 1497: jump = JUMP(SLJIT_C_NOT_ZERO);
! 1498: /* 4 byte sequence */
! 1499: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 1);
! 1500: OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x07);
! 1501: OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 18);
! 1502: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1503: OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 12);
! 1504: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1505: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 2);
! 1506: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1507: OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
! 1508: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1509: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 3);
! 1510: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 3);
! 1511: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1512: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1513: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 3);
! 1514: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 1515: JUMPHERE(jump);
! 1516:
! 1517: /* 5 byte sequence */
! 1518: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 1);
! 1519: OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x03);
! 1520: OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 24);
! 1521: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1522: OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 18);
! 1523: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1524: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 2);
! 1525: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1526: OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 12);
! 1527: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1528: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 3);
! 1529: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1530: OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
! 1531: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1532: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 4);
! 1533: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 4);
! 1534: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
! 1535: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
! 1536: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 4);
! 1537: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 1538: }
! 1539:
! 1540: static void do_utf8readtype8(compiler_common *common)
! 1541: {
! 1542: /* Fast decoding an utf8 character type. TMP2 contains the first byte
! 1543: of the character (>= 0xc0) and TMP1 is destroyed. Return value in TMP1. */
! 1544: DEFINE_COMPILER;
! 1545: struct sljit_jump *jump;
! 1546: struct sljit_jump *compare;
! 1547:
! 1548: sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
! 1549:
! 1550: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x20);
! 1551: jump = JUMP(SLJIT_C_NOT_ZERO);
! 1552: /* 2 byte sequence */
! 1553: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1554: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1555: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x1f);
! 1556: OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
! 1557: OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
! 1558: OP2(SLJIT_OR, TMP2, 0, TMP2, 0, TMP1, 0);
! 1559: compare = CMP(SLJIT_C_GREATER, TMP2, 0, SLJIT_IMM, 255);
! 1560: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
! 1561: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 1562:
! 1563: JUMPHERE(compare);
! 1564: OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
! 1565: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 1566: JUMPHERE(jump);
! 1567:
! 1568: /* We only have types for characters less than 256. */
! 1569: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), (sljit_w)_pcre_utf8_char_sizes - 0xc0);
! 1570: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
! 1571: OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
! 1572: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 1573: }
! 1574:
! 1575: #endif
! 1576:
! 1577: #ifdef SUPPORT_UCP
! 1578:
! 1579: /* UCD_BLOCK_SIZE must be 128 (see the assert below). */
! 1580: #define UCD_BLOCK_MASK 127
! 1581: #define UCD_BLOCK_SHIFT 7
! 1582:
! 1583: static void do_getucd(compiler_common *common)
! 1584: {
! 1585: /* Search the UCD record for the character comes in TMP1.
! 1586: Returns chartype in TMP1 and UCD offset in TMP2. */
! 1587: DEFINE_COMPILER;
! 1588:
! 1589: SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 8);
! 1590:
! 1591: sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
! 1592: OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
! 1593: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_w)_pcre_ucd_stage1);
! 1594: OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK);
! 1595: OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
! 1596: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
! 1597: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_w)_pcre_ucd_stage2);
! 1598: OP1(SLJIT_MOV_UH, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1);
! 1599: OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_w)_pcre_ucd_records + SLJIT_OFFSETOF(ucd_record, chartype));
! 1600: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3);
! 1601: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 1602: }
! 1603: #endif
! 1604:
! 1605: static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common, BOOL hascrorlf, BOOL firstline)
! 1606: {
! 1607: DEFINE_COMPILER;
! 1608: struct sljit_label *mainloop;
! 1609: struct sljit_label *newlinelabel = NULL;
! 1610: struct sljit_jump *start;
! 1611: struct sljit_jump *end = NULL;
! 1612: struct sljit_jump *nl = NULL;
! 1613: #ifdef SUPPORT_UTF8
! 1614: struct sljit_jump *singlebyte;
! 1615: #endif
! 1616: jump_list *newline = NULL;
! 1617: BOOL newlinecheck = FALSE;
! 1618: BOOL readbyte = FALSE;
! 1619:
! 1620: if (!(hascrorlf || firstline) && (common->nltype == NLTYPE_ANY ||
! 1621: common->nltype == NLTYPE_ANYCRLF || common->newline > 255))
! 1622: newlinecheck = TRUE;
! 1623:
! 1624: if (firstline)
! 1625: {
! 1626: /* Search for the end of the first line. */
! 1627: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, STR_PTR, 0);
! 1628: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), FIRSTLINE_END, STR_END, 0);
! 1629:
! 1630: if (common->nltype == NLTYPE_FIXED && common->newline > 255)
! 1631: {
! 1632: mainloop = LABEL();
! 1633: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1634: end = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 1635: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), -1);
! 1636: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 0);
! 1637: CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, mainloop);
! 1638: CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, mainloop);
! 1639: OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_LOCALS_REG), FIRSTLINE_END, STR_PTR, 0, SLJIT_IMM, 1);
! 1640: }
! 1641: else
! 1642: {
! 1643: end = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 1644: mainloop = LABEL();
! 1645: /* Continual stores does not cause data dependency. */
! 1646: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), FIRSTLINE_END, STR_PTR, 0);
! 1647: read_char(common);
! 1648: check_newlinechar(common, common->nltype, &newline, TRUE);
! 1649: CMPTO(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0, mainloop);
! 1650: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), FIRSTLINE_END, STR_PTR, 0);
! 1651: set_jumps(newline, LABEL());
! 1652: }
! 1653:
! 1654: JUMPHERE(end);
! 1655: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0);
! 1656: }
! 1657:
! 1658: start = JUMP(SLJIT_JUMP);
! 1659:
! 1660: if (newlinecheck)
! 1661: {
! 1662: newlinelabel = LABEL();
! 1663: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1664: end = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 1665: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1666: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff);
! 1667: COND_VALUE(SLJIT_MOV, TMP1, 0, SLJIT_C_EQUAL);
! 1668: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
! 1669: nl = JUMP(SLJIT_JUMP);
! 1670: }
! 1671:
! 1672: mainloop = LABEL();
! 1673:
! 1674: /* Increasing the STR_PTR here requires one less jump in the most common case. */
! 1675: #ifdef SUPPORT_UTF8
! 1676: if (common->utf8) readbyte = TRUE;
! 1677: #endif
! 1678: if (newlinecheck) readbyte = TRUE;
! 1679:
! 1680: if (readbyte)
! 1681: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1682:
! 1683: if (newlinecheck)
! 1684: CMPTO(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, newlinelabel);
! 1685:
! 1686: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1687: #ifdef SUPPORT_UTF8
! 1688: if (common->utf8)
! 1689: {
! 1690: singlebyte = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
! 1691: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)_pcre_utf8_char_sizes - 0xc0);
! 1692: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
! 1693: JUMPHERE(singlebyte);
! 1694: }
! 1695: #endif
! 1696: JUMPHERE(start);
! 1697:
! 1698: if (newlinecheck)
! 1699: {
! 1700: JUMPHERE(end);
! 1701: JUMPHERE(nl);
! 1702: }
! 1703:
! 1704: return mainloop;
! 1705: }
! 1706:
! 1707: static SLJIT_INLINE void fast_forward_first_byte(compiler_common *common, pcre_uint16 firstbyte, BOOL firstline)
! 1708: {
! 1709: DEFINE_COMPILER;
! 1710: struct sljit_label *start;
! 1711: struct sljit_jump *leave;
! 1712: struct sljit_jump *found;
! 1713: pcre_uint16 oc, bit;
! 1714:
! 1715: if (firstline)
! 1716: {
! 1717: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, STR_END, 0);
! 1718: OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), FIRSTLINE_END);
! 1719: }
! 1720:
! 1721: start = LABEL();
! 1722: leave = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 1723: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1724:
! 1725: if ((firstbyte & REQ_CASELESS) == 0)
! 1726: found = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, firstbyte & 0xff);
! 1727: else
! 1728: {
! 1729: firstbyte &= 0xff;
! 1730: oc = common->fcc[firstbyte];
! 1731: bit = firstbyte ^ oc;
! 1732: if (ispowerof2(bit))
! 1733: {
! 1734: OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, bit);
! 1735: found = CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, firstbyte | bit);
! 1736: }
! 1737: else
! 1738: {
! 1739: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, firstbyte);
! 1740: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL);
! 1741: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, oc);
! 1742: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 1743: found = JUMP(SLJIT_C_NOT_ZERO);
! 1744: }
! 1745: }
! 1746:
! 1747: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1748: #ifdef SUPPORT_UTF8
! 1749: if (common->utf8)
! 1750: {
! 1751: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0, start);
! 1752: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)_pcre_utf8_char_sizes - 0xc0);
! 1753: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
! 1754: }
! 1755: #endif
! 1756: JUMPTO(SLJIT_JUMP, start);
! 1757: JUMPHERE(found);
! 1758: JUMPHERE(leave);
! 1759:
! 1760: if (firstline)
! 1761: OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0);
! 1762: }
! 1763:
! 1764: static SLJIT_INLINE void fast_forward_newline(compiler_common *common, BOOL firstline)
! 1765: {
! 1766: DEFINE_COMPILER;
! 1767: struct sljit_label *loop;
! 1768: struct sljit_jump *lastchar;
! 1769: struct sljit_jump *firstchar;
! 1770: struct sljit_jump *leave;
! 1771: struct sljit_jump *foundcr = NULL;
! 1772: struct sljit_jump *notfoundnl;
! 1773: jump_list *newline = NULL;
! 1774:
! 1775: if (firstline)
! 1776: {
! 1777: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, STR_END, 0);
! 1778: OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), FIRSTLINE_END);
! 1779: }
! 1780:
! 1781: if (common->nltype == NLTYPE_FIXED && common->newline > 255)
! 1782: {
! 1783: lastchar = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 1784: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 1785: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
! 1786: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
! 1787: firstchar = CMP(SLJIT_C_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
! 1788:
! 1789: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 2);
! 1790: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0);
! 1791: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_GREATER_EQUAL);
! 1792: OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
! 1793:
! 1794: loop = LABEL();
! 1795: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1796: leave = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 1797: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), -2);
! 1798: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), -1);
! 1799: CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, loop);
! 1800: CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, loop);
! 1801:
! 1802: JUMPHERE(leave);
! 1803: JUMPHERE(firstchar);
! 1804: JUMPHERE(lastchar);
! 1805:
! 1806: if (firstline)
! 1807: OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0);
! 1808: return;
! 1809: }
! 1810:
! 1811: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 1812: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
! 1813: firstchar = CMP(SLJIT_C_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
! 1814: skip_char_back(common);
! 1815:
! 1816: loop = LABEL();
! 1817: read_char(common);
! 1818: lastchar = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 1819: if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF)
! 1820: foundcr = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
! 1821: check_newlinechar(common, common->nltype, &newline, FALSE);
! 1822: set_jumps(newline, loop);
! 1823:
! 1824: if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF)
! 1825: {
! 1826: leave = JUMP(SLJIT_JUMP);
! 1827: JUMPHERE(foundcr);
! 1828: notfoundnl = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 1829: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1830: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL);
! 1831: COND_VALUE(SLJIT_MOV, TMP1, 0, SLJIT_C_EQUAL);
! 1832: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
! 1833: JUMPHERE(notfoundnl);
! 1834: JUMPHERE(leave);
! 1835: }
! 1836: JUMPHERE(lastchar);
! 1837: JUMPHERE(firstchar);
! 1838:
! 1839: if (firstline)
! 1840: OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0);
! 1841: }
! 1842:
! 1843: static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common, sljit_uw start_bits, BOOL firstline)
! 1844: {
! 1845: DEFINE_COMPILER;
! 1846: struct sljit_label *start;
! 1847: struct sljit_jump *leave;
! 1848: struct sljit_jump *found;
! 1849:
! 1850: if (firstline)
! 1851: {
! 1852: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, STR_END, 0);
! 1853: OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), FIRSTLINE_END);
! 1854: }
! 1855:
! 1856: start = LABEL();
! 1857: leave = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 1858: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 1859: #ifdef SUPPORT_UTF8
! 1860: if (common->utf8)
! 1861: OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
! 1862: #endif
! 1863: OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
! 1864: OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
! 1865: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), start_bits);
! 1866: OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
! 1867: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
! 1868: found = JUMP(SLJIT_C_NOT_ZERO);
! 1869:
! 1870: #ifdef SUPPORT_UTF8
! 1871: if (common->utf8)
! 1872: OP1(SLJIT_MOV, TMP1, 0, TMP3, 0);
! 1873: #endif
! 1874: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1875: #ifdef SUPPORT_UTF8
! 1876: if (common->utf8)
! 1877: {
! 1878: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0, start);
! 1879: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)_pcre_utf8_char_sizes - 0xc0);
! 1880: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
! 1881: }
! 1882: #endif
! 1883: JUMPTO(SLJIT_JUMP, start);
! 1884: JUMPHERE(found);
! 1885: JUMPHERE(leave);
! 1886:
! 1887: if (firstline)
! 1888: OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0);
! 1889: }
! 1890:
! 1891: static SLJIT_INLINE struct sljit_jump *search_requested_char(compiler_common *common, pcre_uint16 reqbyte, BOOL has_firstbyte)
! 1892: {
! 1893: DEFINE_COMPILER;
! 1894: struct sljit_label *loop;
! 1895: struct sljit_jump *toolong;
! 1896: struct sljit_jump *alreadyfound;
! 1897: struct sljit_jump *found;
! 1898: struct sljit_jump *foundoc = NULL;
! 1899: struct sljit_jump *notfound;
! 1900: pcre_uint16 oc, bit;
! 1901:
! 1902: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), REQ_BYTE_PTR);
! 1903: OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, REQ_BYTE_MAX);
! 1904: toolong = CMP(SLJIT_C_LESS, TMP1, 0, STR_END, 0);
! 1905: alreadyfound = CMP(SLJIT_C_LESS, STR_PTR, 0, TMP2, 0);
! 1906:
! 1907: if (has_firstbyte)
! 1908: OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 1909: else
! 1910: OP1(SLJIT_MOV, TMP1, 0, STR_PTR, 0);
! 1911:
! 1912: loop = LABEL();
! 1913: notfound = CMP(SLJIT_C_GREATER_EQUAL, TMP1, 0, STR_END, 0);
! 1914:
! 1915: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), 0);
! 1916: if ((reqbyte & REQ_CASELESS) == 0)
! 1917: found = CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, reqbyte & 0xff);
! 1918: else
! 1919: {
! 1920: reqbyte &= 0xff;
! 1921: oc = common->fcc[reqbyte];
! 1922: bit = reqbyte ^ oc;
! 1923: if (ispowerof2(bit))
! 1924: {
! 1925: OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, bit);
! 1926: found = CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, reqbyte | bit);
! 1927: }
! 1928: else
! 1929: {
! 1930: found = CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, reqbyte);
! 1931: foundoc = CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, oc);
! 1932: }
! 1933: }
! 1934: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 1935: JUMPTO(SLJIT_JUMP, loop);
! 1936:
! 1937: JUMPHERE(found);
! 1938: if (foundoc)
! 1939: JUMPHERE(foundoc);
! 1940: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), REQ_BYTE_PTR, TMP1, 0);
! 1941: JUMPHERE(alreadyfound);
! 1942: JUMPHERE(toolong);
! 1943: return notfound;
! 1944: }
! 1945:
! 1946: static void do_revertframes(compiler_common *common)
! 1947: {
! 1948: DEFINE_COMPILER;
! 1949: struct sljit_jump *jump;
! 1950: struct sljit_label *mainloop;
! 1951:
! 1952: sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
! 1953: OP1(SLJIT_MOV, TMP1, 0, STACK_TOP, 0);
! 1954:
! 1955: /* Drop frames until we reach STACK_TOP. */
! 1956: mainloop = LABEL();
! 1957: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), 0);
! 1958: jump = CMP(SLJIT_C_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, frame_end);
! 1959: OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_LOCALS_REG, 0);
! 1960: OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(TMP1), sizeof(sljit_w));
! 1961: OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_w), SLJIT_MEM1(TMP1), 2 * sizeof(sljit_w));
! 1962: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_w));
! 1963: JUMPTO(SLJIT_JUMP, mainloop);
! 1964:
! 1965: JUMPHERE(jump);
! 1966: jump = CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, frame_end);
! 1967: /* End of dropping frames. */
! 1968: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 1969:
! 1970: JUMPHERE(jump);
! 1971: jump = CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, frame_setstrbegin);
! 1972: /* Set string begin. */
! 1973: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), sizeof(sljit_w));
! 1974: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_w));
! 1975: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), TMP2, 0);
! 1976: JUMPTO(SLJIT_JUMP, mainloop);
! 1977:
! 1978: JUMPHERE(jump);
! 1979: /* Unknown command. */
! 1980: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_w));
! 1981: JUMPTO(SLJIT_JUMP, mainloop);
! 1982: }
! 1983:
! 1984: static void check_wordboundary(compiler_common *common)
! 1985: {
! 1986: DEFINE_COMPILER;
! 1987: struct sljit_jump *beginend;
! 1988: #ifdef SUPPORT_UTF8
! 1989: struct sljit_jump *jump;
! 1990: #endif
! 1991:
! 1992: SLJIT_COMPILE_ASSERT(ctype_word == 0x10, ctype_word_must_be_16);
! 1993:
! 1994: sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, 1, 5, 5, common->localsize);
! 1995: /* Get type of the previous char, and put it to LOCALS1. */
! 1996: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 1997: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
! 1998: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, SLJIT_IMM, 0);
! 1999: beginend = CMP(SLJIT_C_LESS_EQUAL, STR_PTR, 0, TMP1, 0);
! 2000: skip_char_back(common);
! 2001: read_char(common);
! 2002:
! 2003: /* Testing char type. */
! 2004: #ifdef SUPPORT_UCP
! 2005: if (common->useucp)
! 2006: {
! 2007: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
! 2008: jump = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
! 2009: add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
! 2010: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
! 2011: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
! 2012: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2013: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
! 2014: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
! 2015: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2016: JUMPHERE(jump);
! 2017: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, TMP2, 0);
! 2018: }
! 2019: else
! 2020: #endif
! 2021: {
! 2022: #ifdef SUPPORT_UTF8
! 2023: /* Here LOCALS1 has already been zeroed. */
! 2024: jump = NULL;
! 2025: if (common->utf8)
! 2026: jump = CMP(SLJIT_C_GREATER, TMP1, 0, SLJIT_IMM, 255);
! 2027: #endif
! 2028: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), common->ctypes);
! 2029: OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 4 /* ctype_word */);
! 2030: OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 2031: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, TMP1, 0);
! 2032: #ifdef SUPPORT_UTF8
! 2033: if (jump != NULL)
! 2034: JUMPHERE(jump);
! 2035: #endif
! 2036: }
! 2037: JUMPHERE(beginend);
! 2038:
! 2039: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
! 2040: beginend = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 2041: peek_char(common);
! 2042:
! 2043: /* Testing char type. This is a code duplication. */
! 2044: #ifdef SUPPORT_UCP
! 2045: if (common->useucp)
! 2046: {
! 2047: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
! 2048: jump = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
! 2049: add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
! 2050: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
! 2051: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
! 2052: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2053: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
! 2054: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
! 2055: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2056: JUMPHERE(jump);
! 2057: }
! 2058: else
! 2059: #endif
! 2060: {
! 2061: #ifdef SUPPORT_UTF8
! 2062: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
! 2063: jump = NULL;
! 2064: if (common->utf8)
! 2065: jump = CMP(SLJIT_C_GREATER, TMP1, 0, SLJIT_IMM, 255);
! 2066: #endif
! 2067: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), common->ctypes);
! 2068: OP2(SLJIT_LSHR, TMP2, 0, TMP2, 0, SLJIT_IMM, 4 /* ctype_word */);
! 2069: OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
! 2070: #ifdef SUPPORT_UTF8
! 2071: if (jump != NULL)
! 2072: JUMPHERE(jump);
! 2073: #endif
! 2074: }
! 2075: JUMPHERE(beginend);
! 2076:
! 2077: OP2(SLJIT_XOR | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1);
! 2078: sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0);
! 2079: }
! 2080:
! 2081: static void check_anynewline(compiler_common *common)
! 2082: {
! 2083: /* Check whether TMP1 contains a newline character. TMP2 destroyed. */
! 2084: DEFINE_COMPILER;
! 2085:
! 2086: sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
! 2087:
! 2088: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
! 2089: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
! 2090: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2091: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
! 2092: #ifdef SUPPORT_UTF8
! 2093: if (common->utf8)
! 2094: {
! 2095: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL);
! 2096: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
! 2097: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
! 2098: }
! 2099: #endif
! 2100: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 2101: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 2102: }
! 2103:
! 2104: static void check_hspace(compiler_common *common)
! 2105: {
! 2106: /* Check whether TMP1 contains a newline character. TMP2 destroyed. */
! 2107: DEFINE_COMPILER;
! 2108:
! 2109: sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
! 2110:
! 2111: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x09);
! 2112: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL);
! 2113: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20);
! 2114: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL);
! 2115: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0);
! 2116: #ifdef SUPPORT_UTF8
! 2117: if (common->utf8)
! 2118: {
! 2119: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL);
! 2120: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x1680);
! 2121: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL);
! 2122: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e);
! 2123: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL);
! 2124: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2000);
! 2125: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000);
! 2126: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2127: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000);
! 2128: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL);
! 2129: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000);
! 2130: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL);
! 2131: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000);
! 2132: }
! 2133: #endif
! 2134: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 2135:
! 2136: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 2137: }
! 2138:
! 2139: static void check_vspace(compiler_common *common)
! 2140: {
! 2141: /* Check whether TMP1 contains a newline character. TMP2 destroyed. */
! 2142: DEFINE_COMPILER;
! 2143:
! 2144: sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
! 2145:
! 2146: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
! 2147: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
! 2148: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2149: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
! 2150: #ifdef SUPPORT_UTF8
! 2151: if (common->utf8)
! 2152: {
! 2153: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 2154: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
! 2155: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
! 2156: }
! 2157: #endif
! 2158: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 2159:
! 2160: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 2161: }
! 2162:
! 2163: #define CHAR1 STR_END
! 2164: #define CHAR2 STACK_TOP
! 2165:
! 2166: static void do_casefulcmp(compiler_common *common)
! 2167: {
! 2168: DEFINE_COMPILER;
! 2169: struct sljit_jump *jump;
! 2170: struct sljit_label *label;
! 2171:
! 2172: sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
! 2173: OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
! 2174: OP1(SLJIT_MOV, TMP3, 0, CHAR1, 0);
! 2175: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, CHAR2, 0);
! 2176: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 2177: OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2178:
! 2179: label = LABEL();
! 2180: OP1(SLJIT_MOVU_UB, CHAR1, 0, SLJIT_MEM1(TMP1), 1);
! 2181: OP1(SLJIT_MOVU_UB, CHAR2, 0, SLJIT_MEM1(STR_PTR), 1);
! 2182: jump = CMP(SLJIT_C_NOT_EQUAL, CHAR1, 0, CHAR2, 0);
! 2183: OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
! 2184: JUMPTO(SLJIT_C_NOT_ZERO, label);
! 2185:
! 2186: JUMPHERE(jump);
! 2187: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2188: OP1(SLJIT_MOV, CHAR1, 0, TMP3, 0);
! 2189: OP1(SLJIT_MOV, CHAR2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0);
! 2190: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 2191: }
! 2192:
! 2193: #define LCC_TABLE STACK_LIMIT
! 2194:
! 2195: static void do_caselesscmp(compiler_common *common)
! 2196: {
! 2197: DEFINE_COMPILER;
! 2198: struct sljit_jump *jump;
! 2199: struct sljit_label *label;
! 2200:
! 2201: sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
! 2202: OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
! 2203:
! 2204: OP1(SLJIT_MOV, TMP3, 0, LCC_TABLE, 0);
! 2205: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, CHAR1, 0);
! 2206: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, CHAR2, 0);
! 2207: OP1(SLJIT_MOV, LCC_TABLE, 0, SLJIT_IMM, common->lcc);
! 2208: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 2209: OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2210:
! 2211: label = LABEL();
! 2212: OP1(SLJIT_MOVU_UB, CHAR1, 0, SLJIT_MEM1(TMP1), 1);
! 2213: OP1(SLJIT_MOVU_UB, CHAR2, 0, SLJIT_MEM1(STR_PTR), 1);
! 2214: OP1(SLJIT_MOV_UB, CHAR1, 0, SLJIT_MEM2(LCC_TABLE, CHAR1), 0);
! 2215: OP1(SLJIT_MOV_UB, CHAR2, 0, SLJIT_MEM2(LCC_TABLE, CHAR2), 0);
! 2216: jump = CMP(SLJIT_C_NOT_EQUAL, CHAR1, 0, CHAR2, 0);
! 2217: OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
! 2218: JUMPTO(SLJIT_C_NOT_ZERO, label);
! 2219:
! 2220: JUMPHERE(jump);
! 2221: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2222: OP1(SLJIT_MOV, LCC_TABLE, 0, TMP3, 0);
! 2223: OP1(SLJIT_MOV, CHAR1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0);
! 2224: OP1(SLJIT_MOV, CHAR2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1);
! 2225: sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
! 2226: }
! 2227:
! 2228: #undef LCC_TABLE
! 2229: #undef CHAR1
! 2230: #undef CHAR2
! 2231:
! 2232: #ifdef SUPPORT_UTF8
! 2233: #ifdef SUPPORT_UCP
! 2234:
! 2235: static uschar * SLJIT_CALL do_utf8caselesscmp(uschar *src1, jit_arguments *args, uschar *end1)
! 2236: {
! 2237: /* This function would be ineffective to do in JIT level. */
! 2238: int c1, c2;
! 2239: uschar *src2 = args->ptr;
! 2240: uschar *end2 = (uschar*)args->end;
! 2241:
! 2242: while (src1 < end1)
! 2243: {
! 2244: if (src2 >= end2)
! 2245: return 0;
! 2246: GETCHARINC(c1, src1);
! 2247: GETCHARINC(c2, src2);
! 2248: if (c1 != c2 && c1 != UCD_OTHERCASE(c2)) return 0;
! 2249: }
! 2250: return src2;
! 2251: }
! 2252:
! 2253: #endif
! 2254: #endif
! 2255:
! 2256: static uschar *byte_sequence_compare(compiler_common *common, BOOL caseless, uschar *cc,
! 2257: compare_context* context, jump_list **fallbacks)
! 2258: {
! 2259: DEFINE_COMPILER;
! 2260: unsigned int othercasebit = 0;
! 2261: uschar *othercasebyte = NULL;
! 2262: #ifdef SUPPORT_UTF8
! 2263: int utf8length;
! 2264: #endif
! 2265:
! 2266: if (caseless && char_has_othercase(common, cc))
! 2267: {
! 2268: othercasebit = char_get_othercase_bit(common, cc);
! 2269: SLJIT_ASSERT(othercasebit);
! 2270: /* Extracting bit difference info. */
! 2271: othercasebyte = cc + (othercasebit >> 8);
! 2272: othercasebit &= 0xff;
! 2273: }
! 2274:
! 2275: if (context->sourcereg == -1)
! 2276: {
! 2277: #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
! 2278: if (context->length >= 4)
! 2279: OP1(SLJIT_MOV_SI, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
! 2280: else if (context->length >= 2)
! 2281: OP1(SLJIT_MOV_SH, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
! 2282: else
! 2283: #endif
! 2284: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
! 2285: context->sourcereg = TMP2;
! 2286: }
! 2287:
! 2288: #ifdef SUPPORT_UTF8
! 2289: utf8length = 1;
! 2290: if (common->utf8 && *cc >= 0xc0)
! 2291: utf8length += _pcre_utf8_table4[*cc & 0x3f];
! 2292:
! 2293: do
! 2294: {
! 2295: #endif
! 2296:
! 2297: context->length--;
! 2298: #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
! 2299:
! 2300: /* Unaligned read is supported. */
! 2301: if (othercasebit != 0 && othercasebyte == cc)
! 2302: {
! 2303: context->c.asbytes[context->byteptr] = *cc | othercasebit;
! 2304: context->oc.asbytes[context->byteptr] = othercasebit;
! 2305: }
! 2306: else
! 2307: {
! 2308: context->c.asbytes[context->byteptr] = *cc;
! 2309: context->oc.asbytes[context->byteptr] = 0;
! 2310: }
! 2311: context->byteptr++;
! 2312:
! 2313: if (context->byteptr >= 4 || context->length == 0 || (context->byteptr == 2 && context->length == 1))
! 2314: {
! 2315: if (context->length >= 4)
! 2316: OP1(SLJIT_MOV_SI, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
! 2317: else if (context->length >= 2)
! 2318: OP1(SLJIT_MOV_SH, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
! 2319: else if (context->length >= 1)
! 2320: OP1(SLJIT_MOV_UB, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
! 2321: context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1;
! 2322:
! 2323: switch(context->byteptr)
! 2324: {
! 2325: case 4:
! 2326: if (context->oc.asint != 0)
! 2327: OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asint);
! 2328: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asint | context->oc.asint));
! 2329: break;
! 2330:
! 2331: case 2:
! 2332: if (context->oc.asshort != 0)
! 2333: OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asshort);
! 2334: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asshort | context->oc.asshort));
! 2335: break;
! 2336:
! 2337: case 1:
! 2338: if (context->oc.asbyte != 0)
! 2339: OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asbyte);
! 2340: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asbyte | context->oc.asbyte));
! 2341: break;
! 2342:
! 2343: default:
! 2344: SLJIT_ASSERT_STOP();
! 2345: break;
! 2346: }
! 2347: context->byteptr = 0;
! 2348: }
! 2349:
! 2350: #else
! 2351:
! 2352: /* Unaligned read is unsupported. */
! 2353: if (context->length > 0)
! 2354: OP1(SLJIT_MOV_UB, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
! 2355: context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1;
! 2356:
! 2357: if (othercasebit != 0 && othercasebyte == cc)
! 2358: {
! 2359: OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, othercasebit);
! 2360: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc | othercasebit));
! 2361: }
! 2362: else
! 2363: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc));
! 2364:
! 2365: #endif
! 2366:
! 2367: cc++;
! 2368: #ifdef SUPPORT_UTF8
! 2369: utf8length--;
! 2370: }
! 2371: while (utf8length > 0);
! 2372: #endif
! 2373:
! 2374: return cc;
! 2375: }
! 2376:
! 2377: #ifdef SUPPORT_UTF8
! 2378:
! 2379: #define SET_TYPE_OFFSET(value) \
! 2380: if ((value) != typeoffset) \
! 2381: { \
! 2382: if ((value) > typeoffset) \
! 2383: OP2(SLJIT_SUB, typereg, 0, typereg, 0, SLJIT_IMM, (value) - typeoffset); \
! 2384: else \
! 2385: OP2(SLJIT_ADD, typereg, 0, typereg, 0, SLJIT_IMM, typeoffset - (value)); \
! 2386: } \
! 2387: typeoffset = (value);
! 2388:
! 2389: #define SET_CHAR_OFFSET(value) \
! 2390: if ((value) != charoffset) \
! 2391: { \
! 2392: if ((value) > charoffset) \
! 2393: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, (value) - charoffset); \
! 2394: else \
! 2395: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, charoffset - (value)); \
! 2396: } \
! 2397: charoffset = (value);
! 2398:
! 2399: static void compile_xclass_hotpath(compiler_common *common, uschar *cc, jump_list **fallbacks)
! 2400: {
! 2401: DEFINE_COMPILER;
! 2402: jump_list *found = NULL;
! 2403: jump_list **list = (*cc & XCL_NOT) == 0 ? &found : fallbacks;
! 2404: unsigned int c;
! 2405: int compares;
! 2406: struct sljit_jump *jump = NULL;
! 2407: uschar *ccbegin;
! 2408: #ifdef SUPPORT_UCP
! 2409: BOOL needstype = FALSE, needsscript = FALSE, needschar = FALSE;
! 2410: BOOL charsaved = FALSE;
! 2411: int typereg = TMP1, scriptreg = TMP1;
! 2412: unsigned int typeoffset;
! 2413: #endif
! 2414: int invertcmp, numberofcmps;
! 2415: unsigned int charoffset;
! 2416:
! 2417: /* Although SUPPORT_UTF8 must be defined, we are not necessary in utf8 mode. */
! 2418: check_input_end(common, fallbacks);
! 2419: read_char(common);
! 2420:
! 2421: if ((*cc++ & XCL_MAP) != 0)
! 2422: {
! 2423: OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
! 2424: if (common->utf8)
! 2425: jump = CMP(SLJIT_C_GREATER, TMP1, 0, SLJIT_IMM, 255);
! 2426:
! 2427: OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
! 2428: OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
! 2429: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)cc);
! 2430: OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
! 2431: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
! 2432: add_jump(compiler, list, JUMP(SLJIT_C_NOT_ZERO));
! 2433:
! 2434: if (common->utf8)
! 2435: JUMPHERE(jump);
! 2436: OP1(SLJIT_MOV, TMP1, 0, TMP3, 0);
! 2437: #ifdef SUPPORT_UCP
! 2438: charsaved = TRUE;
! 2439: #endif
! 2440: cc += 32;
! 2441: }
! 2442:
! 2443: /* Scanning the necessary info. */
! 2444: ccbegin = cc;
! 2445: compares = 0;
! 2446: while (*cc != XCL_END)
! 2447: {
! 2448: compares++;
! 2449: if (*cc == XCL_SINGLE)
! 2450: {
! 2451: cc += 2;
! 2452: #ifdef SUPPORT_UTF8
! 2453: if (common->utf8 && cc[-1] >= 0xc0) cc += _pcre_utf8_table4[cc[-1] & 0x3f];
! 2454: #endif
! 2455: #ifdef SUPPORT_UCP
! 2456: needschar = TRUE;
! 2457: #endif
! 2458: }
! 2459: else if (*cc == XCL_RANGE)
! 2460: {
! 2461: cc += 2;
! 2462: #ifdef SUPPORT_UTF8
! 2463: if (common->utf8 && cc[-1] >= 0xc0) cc += _pcre_utf8_table4[cc[-1] & 0x3f];
! 2464: #endif
! 2465: cc++;
! 2466: #ifdef SUPPORT_UTF8
! 2467: if (common->utf8 && cc[-1] >= 0xc0) cc += _pcre_utf8_table4[cc[-1] & 0x3f];
! 2468: #endif
! 2469: #ifdef SUPPORT_UCP
! 2470: needschar = TRUE;
! 2471: #endif
! 2472: }
! 2473: #ifdef SUPPORT_UCP
! 2474: else
! 2475: {
! 2476: SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
! 2477: cc++;
! 2478: switch(*cc)
! 2479: {
! 2480: case PT_ANY:
! 2481: break;
! 2482:
! 2483: case PT_LAMP:
! 2484: case PT_GC:
! 2485: case PT_PC:
! 2486: case PT_ALNUM:
! 2487: needstype = TRUE;
! 2488: break;
! 2489:
! 2490: case PT_SC:
! 2491: needsscript = TRUE;
! 2492: break;
! 2493:
! 2494: case PT_SPACE:
! 2495: case PT_PXSPACE:
! 2496: case PT_WORD:
! 2497: needstype = TRUE;
! 2498: needschar = TRUE;
! 2499: break;
! 2500:
! 2501: default:
! 2502: SLJIT_ASSERT_STOP();
! 2503: break;
! 2504: }
! 2505: cc += 2;
! 2506: }
! 2507: #endif
! 2508: }
! 2509:
! 2510: #ifdef SUPPORT_UCP
! 2511: /* Simple register allocation. TMP1 is preferred if possible. */
! 2512: if (needstype || needsscript)
! 2513: {
! 2514: if (needschar && !charsaved)
! 2515: OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
! 2516: add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
! 2517: if (needschar)
! 2518: {
! 2519: if (needstype)
! 2520: {
! 2521: OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
! 2522: typereg = RETURN_ADDR;
! 2523: }
! 2524:
! 2525: if (needsscript)
! 2526: scriptreg = TMP3;
! 2527: OP1(SLJIT_MOV, TMP1, 0, TMP3, 0);
! 2528: }
! 2529: else if (needstype && needsscript)
! 2530: scriptreg = TMP3;
! 2531: /* In all other cases only one of them was specified, and that can goes to TMP1. */
! 2532:
! 2533: if (needsscript)
! 2534: {
! 2535: if (scriptreg == TMP1)
! 2536: {
! 2537: OP1(SLJIT_MOV, scriptreg, 0, SLJIT_IMM, (sljit_w)_pcre_ucd_records + SLJIT_OFFSETOF(ucd_record, script));
! 2538: OP1(SLJIT_MOV_UB, scriptreg, 0, SLJIT_MEM2(scriptreg, TMP2), 3);
! 2539: }
! 2540: else
! 2541: {
! 2542: OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 3);
! 2543: OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, (sljit_w)_pcre_ucd_records + SLJIT_OFFSETOF(ucd_record, script));
! 2544: OP1(SLJIT_MOV_UB, scriptreg, 0, SLJIT_MEM1(TMP2), 0);
! 2545: }
! 2546: }
! 2547: }
! 2548: #endif
! 2549:
! 2550: /* Generating code. */
! 2551: cc = ccbegin;
! 2552: charoffset = 0;
! 2553: numberofcmps = 0;
! 2554: #ifdef SUPPORT_UCP
! 2555: typeoffset = 0;
! 2556: #endif
! 2557:
! 2558: while (*cc != XCL_END)
! 2559: {
! 2560: compares--;
! 2561: invertcmp = (compares == 0 && list != fallbacks);
! 2562: jump = NULL;
! 2563:
! 2564: if (*cc == XCL_SINGLE)
! 2565: {
! 2566: cc ++;
! 2567: #ifdef SUPPORT_UTF8
! 2568: if (common->utf8)
! 2569: {
! 2570: GETCHARINC(c, cc);
! 2571: }
! 2572: else
! 2573: #endif
! 2574: c = *cc++;
! 2575:
! 2576: if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE))
! 2577: {
! 2578: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c - charoffset);
! 2579: COND_VALUE(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL);
! 2580: numberofcmps++;
! 2581: }
! 2582: else if (numberofcmps > 0)
! 2583: {
! 2584: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c - charoffset);
! 2585: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 2586: jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp);
! 2587: numberofcmps = 0;
! 2588: }
! 2589: else
! 2590: {
! 2591: jump = CMP(SLJIT_C_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, c - charoffset);
! 2592: numberofcmps = 0;
! 2593: }
! 2594: }
! 2595: else if (*cc == XCL_RANGE)
! 2596: {
! 2597: cc ++;
! 2598: #ifdef SUPPORT_UTF8
! 2599: if (common->utf8)
! 2600: {
! 2601: GETCHARINC(c, cc);
! 2602: }
! 2603: else
! 2604: #endif
! 2605: c = *cc++;
! 2606: SET_CHAR_OFFSET(c);
! 2607: #ifdef SUPPORT_UTF8
! 2608: if (common->utf8)
! 2609: {
! 2610: GETCHARINC(c, cc);
! 2611: }
! 2612: else
! 2613: #endif
! 2614: c = *cc++;
! 2615: if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE))
! 2616: {
! 2617: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c - charoffset);
! 2618: COND_VALUE(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2619: numberofcmps++;
! 2620: }
! 2621: else if (numberofcmps > 0)
! 2622: {
! 2623: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c - charoffset);
! 2624: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2625: jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp);
! 2626: numberofcmps = 0;
! 2627: }
! 2628: else
! 2629: {
! 2630: jump = CMP(SLJIT_C_LESS_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, c - charoffset);
! 2631: numberofcmps = 0;
! 2632: }
! 2633: }
! 2634: #ifdef SUPPORT_UCP
! 2635: else
! 2636: {
! 2637: if (*cc == XCL_NOTPROP)
! 2638: invertcmp ^= 0x1;
! 2639: cc++;
! 2640: switch(*cc)
! 2641: {
! 2642: case PT_ANY:
! 2643: if (list != fallbacks)
! 2644: {
! 2645: if ((cc[-1] == XCL_NOTPROP && compares > 0) || (cc[-1] == XCL_PROP && compares == 0))
! 2646: continue;
! 2647: }
! 2648: else if (cc[-1] == XCL_NOTPROP)
! 2649: continue;
! 2650: jump = JUMP(SLJIT_JUMP);
! 2651: break;
! 2652:
! 2653: case PT_LAMP:
! 2654: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset);
! 2655: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL);
! 2656: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset);
! 2657: COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL);
! 2658: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset);
! 2659: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 2660: jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp);
! 2661: break;
! 2662:
! 2663: case PT_GC:
! 2664: c = _pcre_ucp_typerange[(int)cc[1] * 2];
! 2665: SET_TYPE_OFFSET(c);
! 2666: jump = CMP(SLJIT_C_LESS_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, _pcre_ucp_typerange[(int)cc[1] * 2 + 1] - c);
! 2667: break;
! 2668:
! 2669: case PT_PC:
! 2670: jump = CMP(SLJIT_C_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, (int)cc[1] - typeoffset);
! 2671: break;
! 2672:
! 2673: case PT_SC:
! 2674: jump = CMP(SLJIT_C_EQUAL ^ invertcmp, scriptreg, 0, SLJIT_IMM, (int)cc[1]);
! 2675: break;
! 2676:
! 2677: case PT_SPACE:
! 2678: case PT_PXSPACE:
! 2679: if (*cc == PT_SPACE)
! 2680: {
! 2681: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
! 2682: jump = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, 11 - charoffset);
! 2683: }
! 2684: SET_CHAR_OFFSET(9);
! 2685: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 13 - 9);
! 2686: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2687: if (*cc == PT_SPACE)
! 2688: JUMPHERE(jump);
! 2689:
! 2690: SET_TYPE_OFFSET(ucp_Zl);
! 2691: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl);
! 2692: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2693: jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp);
! 2694: break;
! 2695:
! 2696: case PT_WORD:
! 2697: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE - charoffset);
! 2698: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL);
! 2699: /* ... fall through */
! 2700:
! 2701: case PT_ALNUM:
! 2702: SET_TYPE_OFFSET(ucp_Ll);
! 2703: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
! 2704: COND_VALUE((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2705: SET_TYPE_OFFSET(ucp_Nd);
! 2706: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd);
! 2707: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_LESS_EQUAL);
! 2708: jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp);
! 2709: break;
! 2710: }
! 2711: cc += 2;
! 2712: }
! 2713: #endif
! 2714:
! 2715: if (jump != NULL)
! 2716: add_jump(compiler, compares > 0 ? list : fallbacks, jump);
! 2717: }
! 2718:
! 2719: if (found != NULL)
! 2720: set_jumps(found, LABEL());
! 2721: }
! 2722:
! 2723: #undef SET_TYPE_OFFSET
! 2724: #undef SET_CHAR_OFFSET
! 2725:
! 2726: #endif
! 2727:
! 2728: static uschar *compile_char1_hotpath(compiler_common *common, uschar type, uschar *cc, jump_list **fallbacks)
! 2729: {
! 2730: DEFINE_COMPILER;
! 2731: int length;
! 2732: unsigned int c, oc, bit;
! 2733: compare_context context;
! 2734: struct sljit_jump *jump[4];
! 2735: #ifdef SUPPORT_UTF8
! 2736: struct sljit_label *label;
! 2737: #ifdef SUPPORT_UCP
! 2738: uschar propdata[5];
! 2739: #endif
! 2740: #endif
! 2741:
! 2742: switch(type)
! 2743: {
! 2744: case OP_SOD:
! 2745: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 2746: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
! 2747: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
! 2748: return cc;
! 2749:
! 2750: case OP_SOM:
! 2751: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 2752: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
! 2753: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
! 2754: return cc;
! 2755:
! 2756: case OP_NOT_WORD_BOUNDARY:
! 2757: case OP_WORD_BOUNDARY:
! 2758: add_jump(compiler, &common->wordboundary, JUMP(SLJIT_FAST_CALL));
! 2759: add_jump(compiler, fallbacks, JUMP(type == OP_NOT_WORD_BOUNDARY ? SLJIT_C_NOT_ZERO : SLJIT_C_ZERO));
! 2760: return cc;
! 2761:
! 2762: case OP_NOT_DIGIT:
! 2763: case OP_DIGIT:
! 2764: check_input_end(common, fallbacks);
! 2765: read_char8_type(common);
! 2766: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit);
! 2767: add_jump(compiler, fallbacks, JUMP(type == OP_DIGIT ? SLJIT_C_ZERO : SLJIT_C_NOT_ZERO));
! 2768: return cc;
! 2769:
! 2770: case OP_NOT_WHITESPACE:
! 2771: case OP_WHITESPACE:
! 2772: check_input_end(common, fallbacks);
! 2773: read_char8_type(common);
! 2774: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_space);
! 2775: add_jump(compiler, fallbacks, JUMP(type == OP_WHITESPACE ? SLJIT_C_ZERO : SLJIT_C_NOT_ZERO));
! 2776: return cc;
! 2777:
! 2778: case OP_NOT_WORDCHAR:
! 2779: case OP_WORDCHAR:
! 2780: check_input_end(common, fallbacks);
! 2781: read_char8_type(common);
! 2782: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_word);
! 2783: add_jump(compiler, fallbacks, JUMP(type == OP_WORDCHAR ? SLJIT_C_ZERO : SLJIT_C_NOT_ZERO));
! 2784: return cc;
! 2785:
! 2786: case OP_ANY:
! 2787: check_input_end(common, fallbacks);
! 2788: read_char(common);
! 2789: if (common->nltype == NLTYPE_FIXED && common->newline > 255)
! 2790: {
! 2791: jump[0] = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff);
! 2792: jump[1] = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 2793: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 2794: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, common->newline & 0xff));
! 2795: JUMPHERE(jump[1]);
! 2796: JUMPHERE(jump[0]);
! 2797: }
! 2798: else
! 2799: check_newlinechar(common, common->nltype, fallbacks, TRUE);
! 2800: return cc;
! 2801:
! 2802: case OP_ALLANY:
! 2803: check_input_end(common, fallbacks);
! 2804: #ifdef SUPPORT_UTF8
! 2805: if (common->utf8)
! 2806: {
! 2807: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 2808: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2809: jump[0] = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
! 2810: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)_pcre_utf8_char_sizes - 0xc0);
! 2811: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
! 2812: JUMPHERE(jump[0]);
! 2813: return cc;
! 2814: }
! 2815: #endif
! 2816: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2817: return cc;
! 2818:
! 2819: case OP_ANYBYTE:
! 2820: check_input_end(common, fallbacks);
! 2821: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2822: return cc;
! 2823:
! 2824: #ifdef SUPPORT_UTF8
! 2825: #ifdef SUPPORT_UCP
! 2826: case OP_NOTPROP:
! 2827: case OP_PROP:
! 2828: propdata[0] = 0;
! 2829: propdata[1] = type == OP_NOTPROP ? XCL_NOTPROP : XCL_PROP;
! 2830: propdata[2] = cc[0];
! 2831: propdata[3] = cc[1];
! 2832: propdata[4] = XCL_END;
! 2833: compile_xclass_hotpath(common, propdata, fallbacks);
! 2834: return cc + 2;
! 2835: #endif
! 2836: #endif
! 2837:
! 2838: case OP_ANYNL:
! 2839: check_input_end(common, fallbacks);
! 2840: read_char(common);
! 2841: jump[0] = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
! 2842: jump[1] = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 2843: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 2844: jump[2] = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
! 2845: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2846: jump[3] = JUMP(SLJIT_JUMP);
! 2847: JUMPHERE(jump[0]);
! 2848: check_newlinechar(common, common->bsr_nltype, fallbacks, FALSE);
! 2849: JUMPHERE(jump[1]);
! 2850: JUMPHERE(jump[2]);
! 2851: JUMPHERE(jump[3]);
! 2852: return cc;
! 2853:
! 2854: case OP_NOT_HSPACE:
! 2855: case OP_HSPACE:
! 2856: check_input_end(common, fallbacks);
! 2857: read_char(common);
! 2858: add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL));
! 2859: add_jump(compiler, fallbacks, JUMP(type == OP_NOT_HSPACE ? SLJIT_C_NOT_ZERO : SLJIT_C_ZERO));
! 2860: return cc;
! 2861:
! 2862: case OP_NOT_VSPACE:
! 2863: case OP_VSPACE:
! 2864: check_input_end(common, fallbacks);
! 2865: read_char(common);
! 2866: add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL));
! 2867: add_jump(compiler, fallbacks, JUMP(type == OP_NOT_VSPACE ? SLJIT_C_NOT_ZERO : SLJIT_C_ZERO));
! 2868: return cc;
! 2869:
! 2870: #ifdef SUPPORT_UCP
! 2871: case OP_EXTUNI:
! 2872: check_input_end(common, fallbacks);
! 2873: read_char(common);
! 2874: add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
! 2875: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Mc);
! 2876: add_jump(compiler, fallbacks, CMP(SLJIT_C_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_Mn - ucp_Mc));
! 2877:
! 2878: label = LABEL();
! 2879: jump[0] = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 2880: OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
! 2881: read_char(common);
! 2882: add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
! 2883: OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Mc);
! 2884: CMPTO(SLJIT_C_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_Mn - ucp_Mc, label);
! 2885:
! 2886: OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
! 2887: JUMPHERE(jump[0]);
! 2888: return cc;
! 2889: #endif
! 2890:
! 2891: case OP_EODN:
! 2892: jump[0] = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
! 2893: if (common->nltype == NLTYPE_FIXED && common->newline > 255)
! 2894: {
! 2895: OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 2);
! 2896: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 2897: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_END, 0));
! 2898: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 1);
! 2899: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
! 2900: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
! 2901: }
! 2902: else if (common->nltype == NLTYPE_FIXED)
! 2903: {
! 2904: OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2905: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 2906: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_END, 0));
! 2907: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline));
! 2908: }
! 2909: else
! 2910: {
! 2911: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 2912: jump[1] = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
! 2913: OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 2);
! 2914: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0);
! 2915: jump[2] = JUMP(SLJIT_C_GREATER);
! 2916: add_jump(compiler, fallbacks, JUMP(SLJIT_C_LESS));
! 2917: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 1);
! 2918: jump[3] = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
! 2919: add_jump(compiler, fallbacks, JUMP(SLJIT_JUMP));
! 2920:
! 2921: JUMPHERE(jump[1]);
! 2922: if (common->nltype == NLTYPE_ANYCRLF)
! 2923: {
! 2924: OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 2925: add_jump(compiler, fallbacks, CMP(SLJIT_C_LESS, TMP2, 0, STR_END, 0));
! 2926: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL));
! 2927: }
! 2928: else
! 2929: {
! 2930: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, STR_PTR, 0);
! 2931: read_char(common);
! 2932: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
! 2933: add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL));
! 2934: add_jump(compiler, fallbacks, JUMP(SLJIT_C_ZERO));
! 2935: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1);
! 2936: }
! 2937: JUMPHERE(jump[2]);
! 2938: JUMPHERE(jump[3]);
! 2939: }
! 2940: JUMPHERE(jump[0]);
! 2941: return cc;
! 2942:
! 2943: case OP_EOD:
! 2944: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
! 2945: return cc;
! 2946:
! 2947: case OP_CIRC:
! 2948: OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
! 2949: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
! 2950: add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER, STR_PTR, 0, TMP1, 0));
! 2951: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol));
! 2952: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
! 2953: return cc;
! 2954:
! 2955: case OP_CIRCM:
! 2956: OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
! 2957: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
! 2958: jump[1] = CMP(SLJIT_C_GREATER, STR_PTR, 0, TMP1, 0);
! 2959: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol));
! 2960: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
! 2961: jump[0] = JUMP(SLJIT_JUMP);
! 2962: JUMPHERE(jump[1]);
! 2963:
! 2964: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, end));
! 2965: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP2, 0, STR_PTR, 0));
! 2966:
! 2967: if (common->nltype == NLTYPE_FIXED && common->newline > 255)
! 2968: {
! 2969: OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 2);
! 2970: add_jump(compiler, fallbacks, CMP(SLJIT_C_LESS, TMP2, 0, TMP1, 0));
! 2971: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), -2);
! 2972: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), -1);
! 2973: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
! 2974: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
! 2975: }
! 2976: else
! 2977: {
! 2978: skip_char_back(common);
! 2979: read_char(common);
! 2980: check_newlinechar(common, common->nltype, fallbacks, FALSE);
! 2981: }
! 2982: JUMPHERE(jump[0]);
! 2983: return cc;
! 2984:
! 2985: case OP_DOLL:
! 2986: OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
! 2987: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol));
! 2988: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
! 2989:
! 2990: if (!common->endonly)
! 2991: compile_char1_hotpath(common, OP_EODN, cc, fallbacks);
! 2992: else
! 2993: add_jump(compiler, fallbacks, CMP(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0));
! 2994: return cc;
! 2995:
! 2996: case OP_DOLLM:
! 2997: jump[1] = CMP(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0);
! 2998: OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
! 2999: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol));
! 3000: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
! 3001: jump[0] = JUMP(SLJIT_JUMP);
! 3002: JUMPHERE(jump[1]);
! 3003:
! 3004: if (common->nltype == NLTYPE_FIXED && common->newline > 255)
! 3005: {
! 3006: OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 2);
! 3007: add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER, TMP2, 0, STR_END, 0));
! 3008: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 3009: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(STR_PTR), 1);
! 3010: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
! 3011: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
! 3012: }
! 3013: else
! 3014: {
! 3015: peek_char(common);
! 3016: check_newlinechar(common, common->nltype, fallbacks, FALSE);
! 3017: }
! 3018: JUMPHERE(jump[0]);
! 3019: return cc;
! 3020:
! 3021: case OP_CHAR:
! 3022: case OP_CHARI:
! 3023: length = 1;
! 3024: #ifdef SUPPORT_UTF8
! 3025: if (common->utf8 && *cc >= 0xc0) length += _pcre_utf8_table4[*cc & 0x3f];
! 3026: #endif
! 3027: if (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0)
! 3028: {
! 3029: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, length);
! 3030: add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER, STR_PTR, 0, STR_END, 0));
! 3031:
! 3032: context.length = length;
! 3033: context.sourcereg = -1;
! 3034: #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
! 3035: context.byteptr = 0;
! 3036: #endif
! 3037: return byte_sequence_compare(common, type == OP_CHARI, cc, &context, fallbacks);
! 3038: }
! 3039: add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
! 3040: read_char(common);
! 3041: #ifdef SUPPORT_UTF8
! 3042: if (common->utf8)
! 3043: {
! 3044: GETCHAR(c, cc);
! 3045: }
! 3046: else
! 3047: #endif
! 3048: c = *cc;
! 3049: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c);
! 3050: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL);
! 3051: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char_othercase(common, c));
! 3052: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 3053: add_jump(compiler, fallbacks, JUMP(SLJIT_C_ZERO));
! 3054: return cc + length;
! 3055:
! 3056: case OP_NOT:
! 3057: case OP_NOTI:
! 3058: length = 1;
! 3059: #ifdef SUPPORT_UTF8
! 3060: if (common->utf8)
! 3061: {
! 3062: if (*cc >= 0xc0) length += _pcre_utf8_table4[*cc & 0x3f];
! 3063:
! 3064: check_input_end(common, fallbacks);
! 3065: GETCHAR(c, cc);
! 3066:
! 3067: if (c <= 127)
! 3068: {
! 3069: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
! 3070: if (type == OP_NOT || !char_has_othercase(common, cc))
! 3071: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, c));
! 3072: else
! 3073: {
! 3074: /* Since UTF8 code page is fixed, we know that c is in [a-z] or [A-Z] range. */
! 3075: OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x20);
! 3076: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, c | 0x20));
! 3077: }
! 3078: /* Skip the variable-length character. */
! 3079: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 3080: jump[0] = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
! 3081: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)_pcre_utf8_char_sizes - 0xc0);
! 3082: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
! 3083: JUMPHERE(jump[0]);
! 3084: return cc + length;
! 3085: }
! 3086: else
! 3087: read_char(common);
! 3088: }
! 3089: else
! 3090: #endif
! 3091: {
! 3092: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 1);
! 3093: add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER, STR_PTR, 0, STR_END, 0));
! 3094: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), -1);
! 3095: c = *cc;
! 3096: }
! 3097:
! 3098: if (type == OP_NOT || !char_has_othercase(common, cc))
! 3099: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, c));
! 3100: else
! 3101: {
! 3102: oc = char_othercase(common, c);
! 3103: bit = c ^ oc;
! 3104: if (ispowerof2(bit))
! 3105: {
! 3106: OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit);
! 3107: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, c | bit));
! 3108: }
! 3109: else
! 3110: {
! 3111: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, c));
! 3112: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, oc));
! 3113: }
! 3114: }
! 3115: return cc + length;
! 3116:
! 3117: case OP_CLASS:
! 3118: case OP_NCLASS:
! 3119: check_input_end(common, fallbacks);
! 3120: read_char(common);
! 3121: #ifdef SUPPORT_UTF8
! 3122: jump[0] = NULL;
! 3123: if (common->utf8)
! 3124: {
! 3125: jump[0] = CMP(SLJIT_C_GREATER, TMP1, 0, SLJIT_IMM, 255);
! 3126: if (type == OP_CLASS)
! 3127: {
! 3128: add_jump(compiler, fallbacks, jump[0]);
! 3129: jump[0] = NULL;
! 3130: }
! 3131: }
! 3132: #endif
! 3133: OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
! 3134: OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
! 3135: OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)cc);
! 3136: OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
! 3137: OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
! 3138: add_jump(compiler, fallbacks, JUMP(SLJIT_C_ZERO));
! 3139: #ifdef SUPPORT_UTF8
! 3140: if (jump[0] != NULL)
! 3141: JUMPHERE(jump[0]);
! 3142: #endif
! 3143: return cc + 32;
! 3144:
! 3145: #ifdef SUPPORT_UTF8
! 3146: case OP_XCLASS:
! 3147: compile_xclass_hotpath(common, cc + LINK_SIZE, fallbacks);
! 3148: return cc + GET(cc, 0) - 1;
! 3149: #endif
! 3150:
! 3151: case OP_REVERSE:
! 3152: length = GET(cc, 0);
! 3153: SLJIT_ASSERT(length > 0);
! 3154: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 3155: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
! 3156: #ifdef SUPPORT_UTF8
! 3157: if (common->utf8)
! 3158: {
! 3159: OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, length);
! 3160: label = LABEL();
! 3161: add_jump(compiler, fallbacks, CMP(SLJIT_C_LESS_EQUAL, STR_PTR, 0, TMP1, 0));
! 3162: skip_char_back(common);
! 3163: OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
! 3164: JUMPTO(SLJIT_C_NOT_ZERO, label);
! 3165: return cc + LINK_SIZE;
! 3166: }
! 3167: #endif
! 3168: OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, length);
! 3169: add_jump(compiler, fallbacks, CMP(SLJIT_C_LESS, STR_PTR, 0, TMP1, 0));
! 3170: return cc + LINK_SIZE;
! 3171: }
! 3172: SLJIT_ASSERT_STOP();
! 3173: return cc;
! 3174: }
! 3175:
! 3176: static SLJIT_INLINE uschar *compile_charn_hotpath(compiler_common *common, uschar *cc, uschar *ccend, jump_list **fallbacks)
! 3177: {
! 3178: /* This function consumes at least one input character. */
! 3179: /* To decrease the number of length checks, we try to concatenate the fixed length character sequences. */
! 3180: DEFINE_COMPILER;
! 3181: uschar *ccbegin = cc;
! 3182: compare_context context;
! 3183: int size;
! 3184:
! 3185: context.length = 0;
! 3186: do
! 3187: {
! 3188: if (cc >= ccend)
! 3189: break;
! 3190:
! 3191: if (*cc == OP_CHAR)
! 3192: {
! 3193: size = 1;
! 3194: #ifdef SUPPORT_UTF8
! 3195: if (common->utf8 && cc[1] >= 0xc0)
! 3196: size += _pcre_utf8_table4[cc[1] & 0x3f];
! 3197: #endif
! 3198: }
! 3199: else if (*cc == OP_CHARI)
! 3200: {
! 3201: size = 1;
! 3202: #ifdef SUPPORT_UTF8
! 3203: if (common->utf8)
! 3204: {
! 3205: if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0)
! 3206: size = 0;
! 3207: else if (cc[1] >= 0xc0)
! 3208: size += _pcre_utf8_table4[cc[1] & 0x3f];
! 3209: }
! 3210: else
! 3211: #endif
! 3212: if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0)
! 3213: size = 0;
! 3214: }
! 3215: else
! 3216: size = 0;
! 3217:
! 3218: cc += 1 + size;
! 3219: context.length += size;
! 3220: }
! 3221: while (size > 0 && context.length <= 128);
! 3222:
! 3223: cc = ccbegin;
! 3224: if (context.length > 0)
! 3225: {
! 3226: /* We have a fixed-length byte sequence. */
! 3227: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, context.length);
! 3228: add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER, STR_PTR, 0, STR_END, 0));
! 3229:
! 3230: context.sourcereg = -1;
! 3231: #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
! 3232: context.byteptr = 0;
! 3233: #endif
! 3234: do cc = byte_sequence_compare(common, *cc == OP_CHARI, cc + 1, &context, fallbacks); while (context.length > 0);
! 3235: return cc;
! 3236: }
! 3237:
! 3238: /* A non-fixed length character will be checked if length == 0. */
! 3239: return compile_char1_hotpath(common, *cc, cc + 1, fallbacks);
! 3240: }
! 3241:
! 3242: static struct sljit_jump *compile_ref_checks(compiler_common *common, uschar *cc, jump_list **fallbacks)
! 3243: {
! 3244: DEFINE_COMPILER;
! 3245: int offset = GET2(cc, 1) << 1;
! 3246:
! 3247: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset));
! 3248: if (!common->jscript_compat)
! 3249: {
! 3250: if (fallbacks == NULL)
! 3251: {
! 3252: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1));
! 3253: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL);
! 3254: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1));
! 3255: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL);
! 3256: return JUMP(SLJIT_C_NOT_ZERO);
! 3257: }
! 3258: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1)));
! 3259: }
! 3260: return CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1));
! 3261: }
! 3262:
! 3263: /* Forward definitions. */
! 3264: static void compile_hotpath(compiler_common *, uschar *, uschar *, fallback_common *);
! 3265: static void compile_fallbackpath(compiler_common *, struct fallback_common *);
! 3266:
! 3267: #define PUSH_FALLBACK(size, ccstart, error) \
! 3268: do \
! 3269: { \
! 3270: fallback = sljit_alloc_memory(compiler, (size)); \
! 3271: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \
! 3272: return error; \
! 3273: memset(fallback, 0, size); \
! 3274: fallback->prev = parent->top; \
! 3275: fallback->cc = (ccstart); \
! 3276: parent->top = fallback; \
! 3277: } \
! 3278: while (0)
! 3279:
! 3280: #define PUSH_FALLBACK_NOVALUE(size, ccstart) \
! 3281: do \
! 3282: { \
! 3283: fallback = sljit_alloc_memory(compiler, (size)); \
! 3284: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \
! 3285: return; \
! 3286: memset(fallback, 0, size); \
! 3287: fallback->prev = parent->top; \
! 3288: fallback->cc = (ccstart); \
! 3289: parent->top = fallback; \
! 3290: } \
! 3291: while (0)
! 3292:
! 3293: #define FALLBACK_AS(type) ((type*)fallback)
! 3294:
! 3295: static uschar *compile_ref_hotpath(compiler_common *common, uschar *cc, jump_list **fallbacks, BOOL withchecks, BOOL emptyfail)
! 3296: {
! 3297: DEFINE_COMPILER;
! 3298: int offset = GET2(cc, 1) << 1;
! 3299: struct sljit_jump *jump = NULL;
! 3300:
! 3301: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset));
! 3302: if (withchecks && !common->jscript_compat)
! 3303: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1)));
! 3304:
! 3305: #ifdef SUPPORT_UTF8
! 3306: #ifdef SUPPORT_UCP
! 3307: if (common->utf8 && *cc == OP_REFI)
! 3308: {
! 3309: SLJIT_ASSERT(TMP1 == SLJIT_TEMPORARY_REG1 && STACK_TOP == SLJIT_TEMPORARY_REG2 && TMP2 == SLJIT_TEMPORARY_REG3);
! 3310: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1));
! 3311: if (withchecks)
! 3312: jump = CMP(SLJIT_C_EQUAL, TMP1, 0, TMP2, 0);
! 3313:
! 3314: /* Needed to save important temporary registers. */
! 3315: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, STACK_TOP, 0);
! 3316: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG2, 0, ARGUMENTS, 0);
! 3317: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), SLJIT_OFFSETOF(jit_arguments, ptr), STR_PTR, 0);
! 3318: sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_utf8caselesscmp));
! 3319: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0);
! 3320: add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0));
! 3321: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
! 3322: }
! 3323: else
! 3324: #endif
! 3325: #endif
! 3326: {
! 3327: OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP1, 0);
! 3328: if (withchecks)
! 3329: jump = JUMP(SLJIT_C_ZERO);
! 3330: OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
! 3331:
! 3332: add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER, STR_PTR, 0, STR_END, 0));
! 3333: add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
! 3334: add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
! 3335: }
! 3336:
! 3337: if (jump != NULL)
! 3338: {
! 3339: if (emptyfail)
! 3340: add_jump(compiler, fallbacks, jump);
! 3341: else
! 3342: JUMPHERE(jump);
! 3343: }
! 3344: return cc + 3;
! 3345: }
! 3346:
! 3347: static SLJIT_INLINE uschar *compile_ref_iterator_hotpath(compiler_common *common, uschar *cc, fallback_common *parent)
! 3348: {
! 3349: DEFINE_COMPILER;
! 3350: fallback_common *fallback;
! 3351: uschar type;
! 3352: struct sljit_label *label;
! 3353: struct sljit_jump *zerolength;
! 3354: struct sljit_jump *jump = NULL;
! 3355: uschar *ccbegin = cc;
! 3356: int min = 0, max = 0;
! 3357: BOOL minimize;
! 3358:
! 3359: PUSH_FALLBACK(sizeof(iterator_fallback), cc, NULL);
! 3360:
! 3361: type = cc[3];
! 3362: minimize = (type & 0x1) != 0;
! 3363: switch(type)
! 3364: {
! 3365: case OP_CRSTAR:
! 3366: case OP_CRMINSTAR:
! 3367: min = 0;
! 3368: max = 0;
! 3369: cc += 4;
! 3370: break;
! 3371: case OP_CRPLUS:
! 3372: case OP_CRMINPLUS:
! 3373: min = 1;
! 3374: max = 0;
! 3375: cc += 4;
! 3376: break;
! 3377: case OP_CRQUERY:
! 3378: case OP_CRMINQUERY:
! 3379: min = 0;
! 3380: max = 1;
! 3381: cc += 4;
! 3382: break;
! 3383: case OP_CRRANGE:
! 3384: case OP_CRMINRANGE:
! 3385: min = GET2(cc, 3 + 1);
! 3386: max = GET2(cc, 3 + 3);
! 3387: cc += 8;
! 3388: break;
! 3389: default:
! 3390: SLJIT_ASSERT_STOP();
! 3391: break;
! 3392: }
! 3393:
! 3394: if (!minimize)
! 3395: {
! 3396: if (min == 0)
! 3397: {
! 3398: allocate_stack(common, 2);
! 3399: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 3400: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
! 3401: /* Temporary release of STR_PTR. */
! 3402: OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w));
! 3403: zerolength = compile_ref_checks(common, ccbegin, NULL);
! 3404: /* Restore if not zero length. */
! 3405: OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w));
! 3406: }
! 3407: else
! 3408: {
! 3409: allocate_stack(common, 1);
! 3410: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 3411: zerolength = compile_ref_checks(common, ccbegin, &fallback->topfallbacks);
! 3412: }
! 3413:
! 3414: if (min > 1 || max > 1)
! 3415: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 0);
! 3416:
! 3417: label = LABEL();
! 3418: compile_ref_hotpath(common, ccbegin, &fallback->topfallbacks, FALSE, FALSE);
! 3419:
! 3420: if (min > 1 || max > 1)
! 3421: {
! 3422: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0);
! 3423: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 3424: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, TMP1, 0);
! 3425: if (min > 1)
! 3426: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, min, label);
! 3427: if (max > 1)
! 3428: {
! 3429: jump = CMP(SLJIT_C_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, max);
! 3430: allocate_stack(common, 1);
! 3431: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 3432: JUMPTO(SLJIT_JUMP, label);
! 3433: JUMPHERE(jump);
! 3434: }
! 3435: }
! 3436:
! 3437: if (max == 0)
! 3438: {
! 3439: /* Includes min > 1 case as well. */
! 3440: allocate_stack(common, 1);
! 3441: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 3442: JUMPTO(SLJIT_JUMP, label);
! 3443: }
! 3444:
! 3445: JUMPHERE(zerolength);
! 3446: FALLBACK_AS(iterator_fallback)->hotpath = LABEL();
! 3447:
! 3448: decrease_call_count(common);
! 3449: return cc;
! 3450: }
! 3451:
! 3452: allocate_stack(common, 2);
! 3453: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 3454: if (type != OP_CRMINSTAR)
! 3455: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
! 3456:
! 3457: if (min == 0)
! 3458: {
! 3459: zerolength = compile_ref_checks(common, ccbegin, NULL);
! 3460: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 3461: jump = JUMP(SLJIT_JUMP);
! 3462: }
! 3463: else
! 3464: zerolength = compile_ref_checks(common, ccbegin, &fallback->topfallbacks);
! 3465:
! 3466: FALLBACK_AS(iterator_fallback)->hotpath = LABEL();
! 3467: if (max > 0)
! 3468: add_jump(compiler, &fallback->topfallbacks, CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, max));
! 3469:
! 3470: compile_ref_hotpath(common, ccbegin, &fallback->topfallbacks, TRUE, TRUE);
! 3471: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 3472:
! 3473: if (min > 1)
! 3474: {
! 3475: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 3476: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 3477: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
! 3478: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, min, FALLBACK_AS(iterator_fallback)->hotpath);
! 3479: }
! 3480: else if (max > 0)
! 3481: OP2(SLJIT_ADD, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1);
! 3482:
! 3483: if (jump != NULL)
! 3484: JUMPHERE(jump);
! 3485: JUMPHERE(zerolength);
! 3486:
! 3487: decrease_call_count(common);
! 3488: return cc;
! 3489: }
! 3490:
! 3491: static SLJIT_INLINE uschar *compile_recurse_hotpath(compiler_common *common, uschar *cc, fallback_common *parent)
! 3492: {
! 3493: DEFINE_COMPILER;
! 3494: fallback_common *fallback;
! 3495: recurse_entry *entry = common->entries;
! 3496: recurse_entry *prev = NULL;
! 3497: int start = GET(cc, 1);
! 3498:
! 3499: PUSH_FALLBACK(sizeof(recurse_fallback), cc, NULL);
! 3500: while (entry != NULL)
! 3501: {
! 3502: if (entry->start == start)
! 3503: break;
! 3504: prev = entry;
! 3505: entry = entry->next;
! 3506: }
! 3507:
! 3508: if (entry == NULL)
! 3509: {
! 3510: entry = sljit_alloc_memory(compiler, sizeof(recurse_entry));
! 3511: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 3512: return NULL;
! 3513: entry->next = NULL;
! 3514: entry->entry = NULL;
! 3515: entry->calls = NULL;
! 3516: entry->start = start;
! 3517:
! 3518: if (prev != NULL)
! 3519: prev->next = entry;
! 3520: else
! 3521: common->entries = entry;
! 3522: }
! 3523:
! 3524: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0));
! 3525: allocate_stack(common, 1);
! 3526: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
! 3527:
! 3528: if (entry->entry == NULL)
! 3529: add_jump(compiler, &entry->calls, JUMP(SLJIT_FAST_CALL));
! 3530: else
! 3531: JUMPTO(SLJIT_FAST_CALL, entry->entry);
! 3532: /* Leave if the match is failed. */
! 3533: add_jump(compiler, &fallback->topfallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, 0));
! 3534: return cc + 1 + LINK_SIZE;
! 3535: }
! 3536:
! 3537: static uschar *compile_assert_hotpath(compiler_common *common, uschar *cc, assert_fallback *fallback, BOOL conditional)
! 3538: {
! 3539: DEFINE_COMPILER;
! 3540: int framesize;
! 3541: int localptr;
! 3542: fallback_common altfallback;
! 3543: uschar *ccbegin;
! 3544: uschar opcode;
! 3545: uschar bra = OP_BRA;
! 3546: jump_list *tmp = NULL;
! 3547: jump_list **target = (conditional) ? &fallback->condfailed : &fallback->common.topfallbacks;
! 3548: jump_list **found;
! 3549: /* Saving previous accept variables. */
! 3550: struct sljit_label *save_acceptlabel = common->acceptlabel;
! 3551: struct sljit_jump *jump;
! 3552: struct sljit_jump *brajump = NULL;
! 3553: jump_list *save_accept = common->accept;
! 3554:
! 3555: if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
! 3556: {
! 3557: SLJIT_ASSERT(!conditional);
! 3558: bra = *cc;
! 3559: cc++;
! 3560: }
! 3561: localptr = PRIV(cc);
! 3562: SLJIT_ASSERT(localptr != 0);
! 3563: framesize = get_framesize(common, cc, FALSE);
! 3564: fallback->framesize = framesize;
! 3565: fallback->localptr = localptr;
! 3566: opcode = *cc;
! 3567: SLJIT_ASSERT(opcode >= OP_ASSERT && opcode <= OP_ASSERTBACK_NOT);
! 3568: found = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) ? &tmp : target;
! 3569: ccbegin = cc;
! 3570: cc += GET(cc, 1);
! 3571:
! 3572: if (bra == OP_BRAMINZERO)
! 3573: {
! 3574: /* This is a braminzero fallback path. */
! 3575: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 3576: free_stack(common, 1);
! 3577: brajump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
! 3578: }
! 3579:
! 3580: if (framesize < 0)
! 3581: {
! 3582: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0);
! 3583: allocate_stack(common, 1);
! 3584: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 3585: }
! 3586: else
! 3587: {
! 3588: allocate_stack(common, framesize + 2);
! 3589: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 3590: OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, -STACK(framesize + 1));
! 3591: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP2, 0);
! 3592: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 3593: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
! 3594: init_frame(common, ccbegin, framesize + 1, 2, FALSE);
! 3595: }
! 3596:
! 3597: memset(&altfallback, 0, sizeof(fallback_common));
! 3598: while (1)
! 3599: {
! 3600: common->acceptlabel = NULL;
! 3601: common->accept = NULL;
! 3602: altfallback.top = NULL;
! 3603: altfallback.topfallbacks = NULL;
! 3604:
! 3605: if (*ccbegin == OP_ALT)
! 3606: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 3607:
! 3608: altfallback.cc = ccbegin;
! 3609: compile_hotpath(common, ccbegin + 1 + LINK_SIZE, cc, &altfallback);
! 3610: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 3611: {
! 3612: common->acceptlabel = save_acceptlabel;
! 3613: common->accept = save_accept;
! 3614: return NULL;
! 3615: }
! 3616: common->acceptlabel = LABEL();
! 3617: if (common->accept != NULL)
! 3618: set_jumps(common->accept, common->acceptlabel);
! 3619:
! 3620: /* Reset stack. */
! 3621: if (framesize < 0)
! 3622: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 3623: else {
! 3624: if ((opcode != OP_ASSERT_NOT && opcode != OP_ASSERTBACK_NOT) || conditional)
! 3625: {
! 3626: /* We don't need to keep the STR_PTR, only the previous localptr. */
! 3627: OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_w));
! 3628: }
! 3629: else
! 3630: {
! 3631: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 3632: add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
! 3633: }
! 3634: }
! 3635:
! 3636: if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT)
! 3637: {
! 3638: /* We know that STR_PTR was stored on the top of the stack. */
! 3639: if (conditional)
! 3640: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0);
! 3641: else if (bra == OP_BRAZERO)
! 3642: {
! 3643: if (framesize < 0)
! 3644: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0);
! 3645: else
! 3646: {
! 3647: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_w));
! 3648: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (framesize + 1) * sizeof(sljit_w));
! 3649: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0);
! 3650: }
! 3651: OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w));
! 3652: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 3653: }
! 3654: else if (framesize >= 0)
! 3655: {
! 3656: /* For OP_BRA and OP_BRAMINZERO. */
! 3657: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_w));
! 3658: }
! 3659: }
! 3660: add_jump(compiler, found, JUMP(SLJIT_JUMP));
! 3661:
! 3662: compile_fallbackpath(common, altfallback.top);
! 3663: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 3664: {
! 3665: common->acceptlabel = save_acceptlabel;
! 3666: common->accept = save_accept;
! 3667: return NULL;
! 3668: }
! 3669: set_jumps(altfallback.topfallbacks, LABEL());
! 3670:
! 3671: if (*cc != OP_ALT)
! 3672: break;
! 3673:
! 3674: ccbegin = cc;
! 3675: cc += GET(cc, 1);
! 3676: }
! 3677: /* None of them matched. */
! 3678:
! 3679: if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
! 3680: {
! 3681: /* Assert is failed. */
! 3682: if (conditional || bra == OP_BRAZERO)
! 3683: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 3684:
! 3685: if (framesize < 0)
! 3686: {
! 3687: /* The topmost item should be 0. */
! 3688: if (bra == OP_BRAZERO)
! 3689: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 3690: else
! 3691: free_stack(common, 1);
! 3692: }
! 3693: else
! 3694: {
! 3695: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 3696: /* The topmost item should be 0. */
! 3697: if (bra == OP_BRAZERO)
! 3698: {
! 3699: free_stack(common, framesize + 1);
! 3700: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 3701: }
! 3702: else
! 3703: free_stack(common, framesize + 2);
! 3704: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0);
! 3705: }
! 3706: jump = JUMP(SLJIT_JUMP);
! 3707: if (bra != OP_BRAZERO)
! 3708: add_jump(compiler, target, jump);
! 3709:
! 3710: /* Assert is successful. */
! 3711: set_jumps(tmp, LABEL());
! 3712: if (framesize < 0)
! 3713: {
! 3714: /* We know that STR_PTR was stored on the top of the stack. */
! 3715: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0);
! 3716: /* Keep the STR_PTR on the top of the stack. */
! 3717: if (bra == OP_BRAZERO)
! 3718: OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w));
! 3719: else if (bra == OP_BRAMINZERO)
! 3720: {
! 3721: OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w));
! 3722: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 3723: }
! 3724: }
! 3725: else
! 3726: {
! 3727: if (bra == OP_BRA)
! 3728: {
! 3729: /* We don't need to keep the STR_PTR, only the previous localptr. */
! 3730: OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_w));
! 3731: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0);
! 3732: }
! 3733: else
! 3734: {
! 3735: /* We don't need to keep the STR_PTR, only the previous localptr. */
! 3736: OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_w));
! 3737: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 3738: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), bra == OP_BRAZERO ? STR_PTR : SLJIT_IMM, 0);
! 3739: }
! 3740: }
! 3741:
! 3742: if (bra == OP_BRAZERO)
! 3743: {
! 3744: fallback->hotpath = LABEL();
! 3745: sljit_set_label(jump, fallback->hotpath);
! 3746: }
! 3747: else if (bra == OP_BRAMINZERO)
! 3748: {
! 3749: JUMPTO(SLJIT_JUMP, fallback->hotpath);
! 3750: JUMPHERE(brajump);
! 3751: if (framesize >= 0)
! 3752: {
! 3753: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 3754: add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
! 3755: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_w));
! 3756: }
! 3757: set_jumps(fallback->common.topfallbacks, LABEL());
! 3758: }
! 3759: }
! 3760: else
! 3761: {
! 3762: /* AssertNot is successful. */
! 3763: if (framesize < 0)
! 3764: {
! 3765: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 3766: if (bra != OP_BRA)
! 3767: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 3768: else
! 3769: free_stack(common, 1);
! 3770: }
! 3771: else
! 3772: {
! 3773: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 3774: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 3775: /* The topmost item should be 0. */
! 3776: if (bra != OP_BRA)
! 3777: {
! 3778: free_stack(common, framesize + 1);
! 3779: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 3780: }
! 3781: else
! 3782: free_stack(common, framesize + 2);
! 3783: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0);
! 3784: }
! 3785:
! 3786: if (bra == OP_BRAZERO)
! 3787: fallback->hotpath = LABEL();
! 3788: else if (bra == OP_BRAMINZERO)
! 3789: {
! 3790: JUMPTO(SLJIT_JUMP, fallback->hotpath);
! 3791: JUMPHERE(brajump);
! 3792: }
! 3793:
! 3794: if (bra != OP_BRA)
! 3795: {
! 3796: SLJIT_ASSERT(found == &fallback->common.topfallbacks);
! 3797: set_jumps(fallback->common.topfallbacks, LABEL());
! 3798: fallback->common.topfallbacks = NULL;
! 3799: }
! 3800: }
! 3801:
! 3802: common->acceptlabel = save_acceptlabel;
! 3803: common->accept = save_accept;
! 3804: return cc + 1 + LINK_SIZE;
! 3805: }
! 3806:
! 3807: static sljit_w SLJIT_CALL do_searchovector(sljit_w refno, sljit_w* locals, uschar *name_table)
! 3808: {
! 3809: int condition = FALSE;
! 3810: uschar *slotA = name_table;
! 3811: uschar *slotB;
! 3812: sljit_w name_count = locals[LOCALS0 / sizeof(sljit_w)];
! 3813: sljit_w name_entry_size = locals[LOCALS1 / sizeof(sljit_w)];
! 3814: sljit_w no_capture;
! 3815: int i;
! 3816:
! 3817: locals += OVECTOR_START / sizeof(sljit_w);
! 3818: no_capture = locals[1];
! 3819:
! 3820: for (i = 0; i < name_count; i++)
! 3821: {
! 3822: if (GET2(slotA, 0) == refno) break;
! 3823: slotA += name_entry_size;
! 3824: }
! 3825:
! 3826: if (i < name_count)
! 3827: {
! 3828: /* Found a name for the number - there can be only one; duplicate names
! 3829: for different numbers are allowed, but not vice versa. First scan down
! 3830: for duplicates. */
! 3831:
! 3832: slotB = slotA;
! 3833: while (slotB > name_table)
! 3834: {
! 3835: slotB -= name_entry_size;
! 3836: if (strcmp((char *)slotA + 2, (char *)slotB + 2) == 0)
! 3837: {
! 3838: condition = locals[GET2(slotB, 0) << 1] != no_capture;
! 3839: if (condition) break;
! 3840: }
! 3841: else break;
! 3842: }
! 3843:
! 3844: /* Scan up for duplicates */
! 3845: if (!condition)
! 3846: {
! 3847: slotB = slotA;
! 3848: for (i++; i < name_count; i++)
! 3849: {
! 3850: slotB += name_entry_size;
! 3851: if (strcmp((char *)slotA + 2, (char *)slotB + 2) == 0)
! 3852: {
! 3853: condition = locals[GET2(slotB, 0) << 1] != no_capture;
! 3854: if (condition) break;
! 3855: }
! 3856: else break;
! 3857: }
! 3858: }
! 3859: }
! 3860: return condition;
! 3861: }
! 3862:
! 3863: static sljit_w SLJIT_CALL do_searchgroups(sljit_w recno, sljit_w* locals, uschar *name_table)
! 3864: {
! 3865: int condition = FALSE;
! 3866: uschar *slotA = name_table;
! 3867: uschar *slotB;
! 3868: sljit_w name_count = locals[LOCALS0 / sizeof(sljit_w)];
! 3869: sljit_w name_entry_size = locals[LOCALS1 / sizeof(sljit_w)];
! 3870: sljit_w group_num = locals[POSSESSIVE0 / sizeof(sljit_w)];
! 3871: int i;
! 3872:
! 3873: for (i = 0; i < name_count; i++)
! 3874: {
! 3875: if (GET2(slotA, 0) == recno) break;
! 3876: slotA += name_entry_size;
! 3877: }
! 3878:
! 3879: if (i < name_count)
! 3880: {
! 3881: /* Found a name for the number - there can be only one; duplicate
! 3882: names for different numbers are allowed, but not vice versa. First
! 3883: scan down for duplicates. */
! 3884:
! 3885: slotB = slotA;
! 3886: while (slotB > name_table)
! 3887: {
! 3888: slotB -= name_entry_size;
! 3889: if (strcmp((char *)slotA + 2, (char *)slotB + 2) == 0)
! 3890: {
! 3891: condition = GET2(slotB, 0) == group_num;
! 3892: if (condition) break;
! 3893: }
! 3894: else break;
! 3895: }
! 3896:
! 3897: /* Scan up for duplicates */
! 3898: if (!condition)
! 3899: {
! 3900: slotB = slotA;
! 3901: for (i++; i < name_count; i++)
! 3902: {
! 3903: slotB += name_entry_size;
! 3904: if (strcmp((char *)slotA + 2, (char *)slotB + 2) == 0)
! 3905: {
! 3906: condition = GET2(slotB, 0) == group_num;
! 3907: if (condition) break;
! 3908: }
! 3909: else break;
! 3910: }
! 3911: }
! 3912: }
! 3913: return condition;
! 3914: }
! 3915:
! 3916: /*
! 3917: Handling bracketed expressions is probably the most complex part.
! 3918:
! 3919: Stack layout naming characters:
! 3920: S - Push the current STR_PTR
! 3921: 0 - Push a 0 (NULL)
! 3922: A - Push the current STR_PTR. Needed for restoring the STR_PTR
! 3923: before the next alternative. Not pushed if there are no alternatives.
! 3924: M - Any values pushed by the current alternative. Can be empty, or anything.
! 3925: C - Push the previous OVECTOR(i), OVECTOR(i+1) and OVECTOR_PRIV(i) to the stack.
! 3926: L - Push the previous local (pointed by localptr) to the stack
! 3927: () - opional values stored on the stack
! 3928: ()* - optonal, can be stored multiple times
! 3929:
! 3930: The following list shows the regular expression templates, their PCRE byte codes
! 3931: and stack layout supported by pcre-sljit.
! 3932:
! 3933: (?:) OP_BRA | OP_KET A M
! 3934: () OP_CBRA | OP_KET C M
! 3935: (?:)+ OP_BRA | OP_KETRMAX 0 A M S ( A M S )*
! 3936: OP_SBRA | OP_KETRMAX 0 L M S ( L M S )*
! 3937: (?:)+? OP_BRA | OP_KETRMIN 0 A M S ( A M S )*
! 3938: OP_SBRA | OP_KETRMIN 0 L M S ( L M S )*
! 3939: ()+ OP_CBRA | OP_KETRMAX 0 C M S ( C M S )*
! 3940: OP_SCBRA | OP_KETRMAX 0 C M S ( C M S )*
! 3941: ()+? OP_CBRA | OP_KETRMIN 0 C M S ( C M S )*
! 3942: OP_SCBRA | OP_KETRMIN 0 C M S ( C M S )*
! 3943: (?:)? OP_BRAZERO | OP_BRA | OP_KET S ( A M 0 )
! 3944: (?:)?? OP_BRAMINZERO | OP_BRA | OP_KET S ( A M 0 )
! 3945: ()? OP_BRAZERO | OP_CBRA | OP_KET S ( C M 0 )
! 3946: ()?? OP_BRAMINZERO | OP_CBRA | OP_KET S ( C M 0 )
! 3947: (?:)* OP_BRAZERO | OP_BRA | OP_KETRMAX S 0 ( A M S )*
! 3948: OP_BRAZERO | OP_SBRA | OP_KETRMAX S 0 ( L M S )*
! 3949: (?:)*? OP_BRAMINZERO | OP_BRA | OP_KETRMIN S 0 ( A M S )*
! 3950: OP_BRAMINZERO | OP_SBRA | OP_KETRMIN S 0 ( L M S )*
! 3951: ()* OP_BRAZERO | OP_CBRA | OP_KETRMAX S 0 ( C M S )*
! 3952: OP_BRAZERO | OP_SCBRA | OP_KETRMAX S 0 ( C M S )*
! 3953: ()*? OP_BRAMINZERO | OP_CBRA | OP_KETRMIN S 0 ( C M S )*
! 3954: OP_BRAMINZERO | OP_SCBRA | OP_KETRMIN S 0 ( C M S )*
! 3955:
! 3956:
! 3957: Stack layout naming characters:
! 3958: A - Push the alternative index (starting from 0) on the stack.
! 3959: Not pushed if there is no alternatives.
! 3960: M - Any values pushed by the current alternative. Can be empty, or anything.
! 3961:
! 3962: The next list shows the possible content of a bracket:
! 3963: (|) OP_*BRA | OP_ALT ... M A
! 3964: (?()|) OP_*COND | OP_ALT M A
! 3965: (?>|) OP_ONCE | OP_ALT ... [stack trace] M A
! 3966: (?>|) OP_ONCE_NC | OP_ALT ... [stack trace] M A
! 3967: Or nothing, if trace is unnecessary
! 3968: */
! 3969:
! 3970: static uschar *compile_bracket_hotpath(compiler_common *common, uschar *cc, fallback_common *parent)
! 3971: {
! 3972: DEFINE_COMPILER;
! 3973: fallback_common *fallback;
! 3974: uschar opcode;
! 3975: int localptr = 0;
! 3976: int offset = 0;
! 3977: int stacksize;
! 3978: uschar *ccbegin;
! 3979: uschar *hotpath;
! 3980: uschar bra = OP_BRA;
! 3981: uschar ket;
! 3982: assert_fallback *assert;
! 3983: BOOL has_alternatives;
! 3984: struct sljit_jump *jump;
! 3985: struct sljit_jump *skip;
! 3986: struct sljit_label *rmaxlabel = NULL;
! 3987: struct sljit_jump *braminzerojump = NULL;
! 3988:
! 3989: PUSH_FALLBACK(sizeof(bracket_fallback), cc, NULL);
! 3990:
! 3991: if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
! 3992: {
! 3993: bra = *cc;
! 3994: cc++;
! 3995: opcode = *cc;
! 3996: }
! 3997:
! 3998: opcode = *cc;
! 3999: ccbegin = cc;
! 4000: hotpath = ccbegin + 1 + LINK_SIZE;
! 4001:
! 4002: if ((opcode == OP_COND || opcode == OP_SCOND) && cc[1 + LINK_SIZE] == OP_DEF)
! 4003: {
! 4004: /* Drop this bracket_fallback. */
! 4005: parent->top = fallback->prev;
! 4006: return bracketend(cc);
! 4007: }
! 4008:
! 4009: ket = *(bracketend(cc) - 1 - LINK_SIZE);
! 4010: SLJIT_ASSERT(ket == OP_KET || ket == OP_KETRMAX || ket == OP_KETRMIN);
! 4011: SLJIT_ASSERT(!((bra == OP_BRAZERO && ket == OP_KETRMIN) || (bra == OP_BRAMINZERO && ket == OP_KETRMAX)));
! 4012: cc += GET(cc, 1);
! 4013:
! 4014: has_alternatives = *cc == OP_ALT;
! 4015: if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
! 4016: {
! 4017: has_alternatives = (*hotpath == OP_RREF) ? FALSE : TRUE;
! 4018: if (*hotpath == OP_NRREF)
! 4019: {
! 4020: stacksize = GET2(hotpath, 1);
! 4021: if (common->currententry == NULL || stacksize == RREF_ANY)
! 4022: has_alternatives = FALSE;
! 4023: else if (common->currententry->start == 0)
! 4024: has_alternatives = stacksize != 0;
! 4025: else
! 4026: has_alternatives = stacksize != GET2(common->start, common->currententry->start + 1 + LINK_SIZE);
! 4027: }
! 4028: }
! 4029:
! 4030: if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN))
! 4031: opcode = OP_SCOND;
! 4032: if (SLJIT_UNLIKELY(opcode == OP_ONCE_NC))
! 4033: opcode = OP_ONCE;
! 4034:
! 4035: if (opcode == OP_CBRA || opcode == OP_SCBRA)
! 4036: {
! 4037: /* Capturing brackets has a pre-allocated space. */
! 4038: offset = GET2(ccbegin, 1 + LINK_SIZE);
! 4039: localptr = OVECTOR_PRIV(offset);
! 4040: offset <<= 1;
! 4041: FALLBACK_AS(bracket_fallback)->localptr = localptr;
! 4042: hotpath += 2;
! 4043: }
! 4044: else if (opcode == OP_ONCE || opcode == OP_SBRA || opcode == OP_SCOND)
! 4045: {
! 4046: /* Other brackets simply allocate the next entry. */
! 4047: localptr = PRIV(ccbegin);
! 4048: SLJIT_ASSERT(localptr != 0);
! 4049: FALLBACK_AS(bracket_fallback)->localptr = localptr;
! 4050: if (opcode == OP_ONCE)
! 4051: FALLBACK_AS(bracket_fallback)->u.framesize = get_framesize(common, ccbegin, FALSE);
! 4052: }
! 4053:
! 4054: /* Instructions before the first alternative. */
! 4055: stacksize = 0;
! 4056: if ((ket == OP_KETRMAX) || (ket == OP_KETRMIN && bra != OP_BRAMINZERO))
! 4057: stacksize++;
! 4058: if (bra == OP_BRAZERO)
! 4059: stacksize++;
! 4060:
! 4061: if (stacksize > 0)
! 4062: allocate_stack(common, stacksize);
! 4063:
! 4064: stacksize = 0;
! 4065: if ((ket == OP_KETRMAX) || (ket == OP_KETRMIN && bra != OP_BRAMINZERO))
! 4066: {
! 4067: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
! 4068: stacksize++;
! 4069: }
! 4070:
! 4071: if (bra == OP_BRAZERO)
! 4072: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
! 4073:
! 4074: if (bra == OP_BRAMINZERO)
! 4075: {
! 4076: /* This is a fallback path! (Since the hot-path of OP_BRAMINZERO matches to the empty string) */
! 4077: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 4078: if (ket != OP_KETRMIN)
! 4079: {
! 4080: free_stack(common, 1);
! 4081: braminzerojump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
! 4082: }
! 4083: else
! 4084: {
! 4085: if (opcode == OP_ONCE || opcode >= OP_SBRA)
! 4086: {
! 4087: jump = CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
! 4088: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 4089: /* Nothing stored during the first run. */
! 4090: skip = JUMP(SLJIT_JUMP);
! 4091: JUMPHERE(jump);
! 4092: /* Checking zero-length iteration. */
! 4093: if (opcode != OP_ONCE || FALLBACK_AS(bracket_fallback)->u.framesize < 0)
! 4094: {
! 4095: /* When we come from outside, localptr contains the previous STR_PTR. */
! 4096: braminzerojump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4097: }
! 4098: else
! 4099: {
! 4100: /* Except when the whole stack frame must be saved. */
! 4101: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4102: braminzerojump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (FALLBACK_AS(bracket_fallback)->u.framesize + 1) * sizeof(sljit_w));
! 4103: }
! 4104: JUMPHERE(skip);
! 4105: }
! 4106: else
! 4107: {
! 4108: jump = CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
! 4109: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 4110: JUMPHERE(jump);
! 4111: }
! 4112: }
! 4113: }
! 4114:
! 4115: if (ket == OP_KETRMIN)
! 4116: FALLBACK_AS(bracket_fallback)->recursivehotpath = LABEL();
! 4117:
! 4118: if (ket == OP_KETRMAX)
! 4119: {
! 4120: rmaxlabel = LABEL();
! 4121: if (has_alternatives && opcode != OP_ONCE && opcode < OP_SBRA)
! 4122: FALLBACK_AS(bracket_fallback)->althotpath = rmaxlabel;
! 4123: }
! 4124:
! 4125: /* Handling capturing brackets and alternatives. */
! 4126: if (opcode == OP_ONCE)
! 4127: {
! 4128: if (FALLBACK_AS(bracket_fallback)->u.framesize < 0)
! 4129: {
! 4130: /* Neither capturing brackets nor recursions are not found in the block. */
! 4131: if (ket == OP_KETRMIN)
! 4132: {
! 4133: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4134: allocate_stack(common, 2);
! 4135: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4136: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
! 4137: OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w));
! 4138: }
! 4139: else if (ket == OP_KETRMAX || has_alternatives)
! 4140: {
! 4141: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0);
! 4142: allocate_stack(common, 1);
! 4143: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4144: }
! 4145: else
! 4146: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0);
! 4147: }
! 4148: else
! 4149: {
! 4150: if (ket == OP_KETRMIN || ket == OP_KETRMAX || has_alternatives)
! 4151: {
! 4152: allocate_stack(common, FALLBACK_AS(bracket_fallback)->u.framesize + 2);
! 4153: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4154: OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, -STACK(FALLBACK_AS(bracket_fallback)->u.framesize + 1));
! 4155: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4156: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP2, 0);
! 4157: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
! 4158: init_frame(common, ccbegin, FALLBACK_AS(bracket_fallback)->u.framesize + 1, 2, FALSE);
! 4159: }
! 4160: else
! 4161: {
! 4162: allocate_stack(common, FALLBACK_AS(bracket_fallback)->u.framesize + 1);
! 4163: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4164: OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, -STACK(FALLBACK_AS(bracket_fallback)->u.framesize));
! 4165: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP2, 0);
! 4166: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
! 4167: init_frame(common, ccbegin, FALLBACK_AS(bracket_fallback)->u.framesize, 1, FALSE);
! 4168: }
! 4169: }
! 4170: }
! 4171: else if (opcode == OP_CBRA || opcode == OP_SCBRA)
! 4172: {
! 4173: /* Saving the previous values. */
! 4174: allocate_stack(common, 3);
! 4175: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset));
! 4176: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1));
! 4177: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
! 4178: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
! 4179: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4180: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STR_PTR, 0);
! 4181: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
! 4182: }
! 4183: else if (opcode == OP_SBRA || opcode == OP_SCOND)
! 4184: {
! 4185: /* Saving the previous value. */
! 4186: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4187: allocate_stack(common, 1);
! 4188: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STR_PTR, 0);
! 4189: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
! 4190: }
! 4191: else if (has_alternatives)
! 4192: {
! 4193: /* Pushing the starting string pointer. */
! 4194: allocate_stack(common, 1);
! 4195: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4196: }
! 4197:
! 4198: /* Generating code for the first alternative. */
! 4199: if (opcode == OP_COND || opcode == OP_SCOND)
! 4200: {
! 4201: if (*hotpath == OP_CREF)
! 4202: {
! 4203: SLJIT_ASSERT(has_alternatives);
! 4204: add_jump(compiler, &(FALLBACK_AS(bracket_fallback)->u.condfailed),
! 4205: CMP(SLJIT_C_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(GET2(hotpath, 1) << 1), SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1)));
! 4206: hotpath += 3;
! 4207: }
! 4208: else if (*hotpath == OP_NCREF)
! 4209: {
! 4210: SLJIT_ASSERT(has_alternatives);
! 4211: stacksize = GET2(hotpath, 1);
! 4212: jump = CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(stacksize << 1), SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1));
! 4213:
! 4214: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STACK_TOP, 0);
! 4215: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, SLJIT_IMM, common->name_count);
! 4216: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, SLJIT_IMM, common->name_entry_size);
! 4217: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG1, 0, SLJIT_IMM, stacksize);
! 4218: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG2, 0, SLJIT_LOCALS_REG, 0);
! 4219: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, common->name_table);
! 4220: sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_searchovector));
! 4221: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1);
! 4222: add_jump(compiler, &(FALLBACK_AS(bracket_fallback)->u.condfailed), CMP(SLJIT_C_EQUAL, SLJIT_TEMPORARY_REG1, 0, SLJIT_IMM, 0));
! 4223:
! 4224: JUMPHERE(jump);
! 4225: hotpath += 3;
! 4226: }
! 4227: else if (*hotpath == OP_RREF || *hotpath == OP_NRREF)
! 4228: {
! 4229: /* Never has other case. */
! 4230: FALLBACK_AS(bracket_fallback)->u.condfailed = NULL;
! 4231:
! 4232: stacksize = GET2(hotpath, 1);
! 4233: if (common->currententry == NULL)
! 4234: stacksize = 0;
! 4235: else if (stacksize == RREF_ANY)
! 4236: stacksize = 1;
! 4237: else if (common->currententry->start == 0)
! 4238: stacksize = stacksize == 0;
! 4239: else
! 4240: stacksize = stacksize == GET2(common->start, common->currententry->start + 1 + LINK_SIZE);
! 4241:
! 4242: if (*hotpath == OP_RREF || stacksize || common->currententry == NULL)
! 4243: {
! 4244: SLJIT_ASSERT(!has_alternatives);
! 4245: if (stacksize != 0)
! 4246: hotpath += 3;
! 4247: else
! 4248: {
! 4249: if (*cc == OP_ALT)
! 4250: {
! 4251: hotpath = cc + 1 + LINK_SIZE;
! 4252: cc += GET(cc, 1);
! 4253: }
! 4254: else
! 4255: hotpath = cc;
! 4256: }
! 4257: }
! 4258: else
! 4259: {
! 4260: SLJIT_ASSERT(has_alternatives);
! 4261:
! 4262: stacksize = GET2(hotpath, 1);
! 4263: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STACK_TOP, 0);
! 4264: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, SLJIT_IMM, common->name_count);
! 4265: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, SLJIT_IMM, common->name_entry_size);
! 4266: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, GET2(common->start, common->currententry->start + 1 + LINK_SIZE));
! 4267: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG1, 0, SLJIT_IMM, stacksize);
! 4268: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG2, 0, SLJIT_LOCALS_REG, 0);
! 4269: OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, common->name_table);
! 4270: sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_searchgroups));
! 4271: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1);
! 4272: add_jump(compiler, &(FALLBACK_AS(bracket_fallback)->u.condfailed), CMP(SLJIT_C_EQUAL, SLJIT_TEMPORARY_REG1, 0, SLJIT_IMM, 0));
! 4273: hotpath += 3;
! 4274: }
! 4275: }
! 4276: else
! 4277: {
! 4278: SLJIT_ASSERT(has_alternatives && *hotpath >= OP_ASSERT && *hotpath <= OP_ASSERTBACK_NOT);
! 4279: /* Similar code as PUSH_FALLBACK macro. */
! 4280: assert = sljit_alloc_memory(compiler, sizeof(assert_fallback));
! 4281: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 4282: return NULL;
! 4283: memset(assert, 0, sizeof(assert_fallback));
! 4284: assert->common.cc = hotpath;
! 4285: FALLBACK_AS(bracket_fallback)->u.assert = assert;
! 4286: hotpath = compile_assert_hotpath(common, hotpath, assert, TRUE);
! 4287: }
! 4288: }
! 4289:
! 4290: compile_hotpath(common, hotpath, cc, fallback);
! 4291: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 4292: return NULL;
! 4293:
! 4294: if (opcode == OP_ONCE)
! 4295: {
! 4296: if (FALLBACK_AS(bracket_fallback)->u.framesize < 0)
! 4297: {
! 4298: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4299: /* TMP2 which is set here used by OP_KETRMAX below. */
! 4300: if (ket == OP_KETRMAX)
! 4301: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), 0);
! 4302: else if (ket == OP_KETRMIN)
! 4303: {
! 4304: /* Move the STR_PTR to the localptr. */
! 4305: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), 0);
! 4306: }
! 4307: }
! 4308: else
! 4309: {
! 4310: stacksize = (ket == OP_KETRMIN || ket == OP_KETRMAX || has_alternatives) ? 2 : 1;
! 4311: OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (FALLBACK_AS(bracket_fallback)->u.framesize + stacksize) * sizeof(sljit_w));
! 4312: if (ket == OP_KETRMAX)
! 4313: {
! 4314: /* TMP2 which is set here used by OP_KETRMAX below. */
! 4315: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 4316: }
! 4317: }
! 4318: }
! 4319:
! 4320: stacksize = 0;
! 4321: if (ket != OP_KET || bra != OP_BRA)
! 4322: stacksize++;
! 4323: if (has_alternatives && opcode != OP_ONCE)
! 4324: stacksize++;
! 4325:
! 4326: if (stacksize > 0)
! 4327: allocate_stack(common, stacksize);
! 4328:
! 4329: stacksize = 0;
! 4330: if (ket != OP_KET)
! 4331: {
! 4332: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
! 4333: stacksize++;
! 4334: }
! 4335: else if (bra != OP_BRA)
! 4336: {
! 4337: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
! 4338: stacksize++;
! 4339: }
! 4340:
! 4341: if (has_alternatives)
! 4342: {
! 4343: if (opcode != OP_ONCE)
! 4344: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
! 4345: if (ket != OP_KETRMAX)
! 4346: FALLBACK_AS(bracket_fallback)->althotpath = LABEL();
! 4347: }
! 4348:
! 4349: /* Must be after the hotpath label. */
! 4350: if (offset != 0)
! 4351: {
! 4352: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4353: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0);
! 4354: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 0), TMP1, 0);
! 4355: }
! 4356:
! 4357: if (ket == OP_KETRMAX)
! 4358: {
! 4359: if (opcode == OP_ONCE || opcode >= OP_SBRA)
! 4360: {
! 4361: if (has_alternatives)
! 4362: FALLBACK_AS(bracket_fallback)->althotpath = LABEL();
! 4363: /* Checking zero-length iteration. */
! 4364: if (opcode != OP_ONCE)
! 4365: CMPTO(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STR_PTR, 0, rmaxlabel);
! 4366: else
! 4367: /* TMP2 must contain the starting STR_PTR. */
! 4368: CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0, rmaxlabel);
! 4369: }
! 4370: else
! 4371: JUMPTO(SLJIT_JUMP, rmaxlabel);
! 4372: FALLBACK_AS(bracket_fallback)->recursivehotpath = LABEL();
! 4373: }
! 4374:
! 4375: if (bra == OP_BRAZERO)
! 4376: FALLBACK_AS(bracket_fallback)->zerohotpath = LABEL();
! 4377:
! 4378: if (bra == OP_BRAMINZERO)
! 4379: {
! 4380: /* This is a fallback path! (From the viewpoint of OP_BRAMINZERO) */
! 4381: JUMPTO(SLJIT_JUMP, ((braminzero_fallback*)parent)->hotpath);
! 4382: if (braminzerojump != NULL)
! 4383: {
! 4384: JUMPHERE(braminzerojump);
! 4385: /* We need to release the end pointer to perform the
! 4386: fallback for the zero-length iteration. When
! 4387: framesize is < 0, OP_ONCE will do the release itself. */
! 4388: if (opcode == OP_ONCE && FALLBACK_AS(bracket_fallback)->u.framesize >= 0)
! 4389: {
! 4390: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4391: add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
! 4392: }
! 4393: else if (ket == OP_KETRMIN && opcode != OP_ONCE)
! 4394: free_stack(common, 1);
! 4395: }
! 4396: /* Continue to the normal fallback. */
! 4397: }
! 4398:
! 4399: if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO)
! 4400: decrease_call_count(common);
! 4401:
! 4402: /* Skip the other alternatives. */
! 4403: while (*cc == OP_ALT)
! 4404: cc += GET(cc, 1);
! 4405: cc += 1 + LINK_SIZE;
! 4406: return cc;
! 4407: }
! 4408:
! 4409: static uschar *compile_bracketpos_hotpath(compiler_common *common, uschar *cc, fallback_common *parent)
! 4410: {
! 4411: DEFINE_COMPILER;
! 4412: fallback_common *fallback;
! 4413: uschar opcode;
! 4414: int localptr;
! 4415: int cbraprivptr = 0;
! 4416: int framesize;
! 4417: int stacksize;
! 4418: int offset = 0;
! 4419: BOOL zero = FALSE;
! 4420: uschar *ccbegin = NULL;
! 4421: int stack;
! 4422: struct sljit_label *loop = NULL;
! 4423: struct jump_list *emptymatch = NULL;
! 4424:
! 4425: PUSH_FALLBACK(sizeof(bracketpos_fallback), cc, NULL);
! 4426: if (*cc == OP_BRAPOSZERO)
! 4427: {
! 4428: zero = TRUE;
! 4429: cc++;
! 4430: }
! 4431:
! 4432: opcode = *cc;
! 4433: localptr = PRIV(cc);
! 4434: SLJIT_ASSERT(localptr != 0);
! 4435: FALLBACK_AS(bracketpos_fallback)->localptr = localptr;
! 4436: switch(opcode)
! 4437: {
! 4438: case OP_BRAPOS:
! 4439: case OP_SBRAPOS:
! 4440: ccbegin = cc + 1 + LINK_SIZE;
! 4441: break;
! 4442:
! 4443: case OP_CBRAPOS:
! 4444: case OP_SCBRAPOS:
! 4445: offset = GET2(cc, 1 + LINK_SIZE);
! 4446: cbraprivptr = OVECTOR_PRIV(offset);
! 4447: offset <<= 1;
! 4448: ccbegin = cc + 1 + LINK_SIZE + 2;
! 4449: break;
! 4450:
! 4451: default:
! 4452: SLJIT_ASSERT_STOP();
! 4453: break;
! 4454: }
! 4455:
! 4456: framesize = get_framesize(common, cc, FALSE);
! 4457: FALLBACK_AS(bracketpos_fallback)->framesize = framesize;
! 4458: if (framesize < 0)
! 4459: {
! 4460: stacksize = (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS) ? 2 : 1;
! 4461: if (!zero)
! 4462: stacksize++;
! 4463: FALLBACK_AS(bracketpos_fallback)->stacksize = stacksize;
! 4464: allocate_stack(common, stacksize);
! 4465: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0);
! 4466:
! 4467: if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS)
! 4468: {
! 4469: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset));
! 4470: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1));
! 4471: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
! 4472: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
! 4473: }
! 4474: else
! 4475: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4476:
! 4477: if (!zero)
! 4478: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 1);
! 4479: }
! 4480: else
! 4481: {
! 4482: stacksize = framesize + 1;
! 4483: if (!zero)
! 4484: stacksize++;
! 4485: if (opcode == OP_BRAPOS || opcode == OP_SBRAPOS)
! 4486: stacksize++;
! 4487: FALLBACK_AS(bracketpos_fallback)->stacksize = stacksize;
! 4488: allocate_stack(common, stacksize);
! 4489:
! 4490: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4491: OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, -STACK(stacksize - 1));
! 4492: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP2, 0);
! 4493: stack = 0;
! 4494: if (!zero)
! 4495: {
! 4496: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 1);
! 4497: stack++;
! 4498: }
! 4499: if (opcode == OP_BRAPOS || opcode == OP_SBRAPOS)
! 4500: {
! 4501: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), STR_PTR, 0);
! 4502: stack++;
! 4503: }
! 4504: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP1, 0);
! 4505: init_frame(common, cc, stacksize - 1, stacksize - framesize, FALSE);
! 4506: }
! 4507:
! 4508: if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS)
! 4509: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr, STR_PTR, 0);
! 4510:
! 4511: loop = LABEL();
! 4512: while (*cc != OP_KETRPOS)
! 4513: {
! 4514: fallback->top = NULL;
! 4515: fallback->topfallbacks = NULL;
! 4516: cc += GET(cc, 1);
! 4517:
! 4518: compile_hotpath(common, ccbegin, cc, fallback);
! 4519: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 4520: return NULL;
! 4521:
! 4522: if (framesize < 0)
! 4523: {
! 4524: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4525:
! 4526: if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS)
! 4527: {
! 4528: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr);
! 4529: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0);
! 4530: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr, STR_PTR, 0);
! 4531: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
! 4532: }
! 4533: else
! 4534: {
! 4535: if (opcode == OP_SBRAPOS)
! 4536: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 4537: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4538: }
! 4539:
! 4540: if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS)
! 4541: add_jump(compiler, &emptymatch, CMP(SLJIT_C_EQUAL, TMP1, 0, STR_PTR, 0));
! 4542:
! 4543: if (!zero)
! 4544: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0);
! 4545: }
! 4546: else
! 4547: {
! 4548: if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS)
! 4549: {
! 4550: OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, stacksize * sizeof(sljit_w));
! 4551: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr);
! 4552: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0);
! 4553: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr, STR_PTR, 0);
! 4554: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
! 4555: }
! 4556: else
! 4557: {
! 4558: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4559: OP2(SLJIT_ADD, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_w));
! 4560: if (opcode == OP_SBRAPOS)
! 4561: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_w));
! 4562: OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_w), STR_PTR, 0);
! 4563: }
! 4564:
! 4565: if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS)
! 4566: add_jump(compiler, &emptymatch, CMP(SLJIT_C_EQUAL, TMP1, 0, STR_PTR, 0));
! 4567:
! 4568: if (!zero)
! 4569: {
! 4570: if (framesize < 0)
! 4571: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0);
! 4572: else
! 4573: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 4574: }
! 4575: }
! 4576: JUMPTO(SLJIT_JUMP, loop);
! 4577: flush_stubs(common);
! 4578:
! 4579: compile_fallbackpath(common, fallback->top);
! 4580: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 4581: return NULL;
! 4582: set_jumps(fallback->topfallbacks, LABEL());
! 4583:
! 4584: if (framesize < 0)
! 4585: {
! 4586: if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS)
! 4587: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr);
! 4588: else
! 4589: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 4590: }
! 4591: else
! 4592: {
! 4593: if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS)
! 4594: {
! 4595: /* Last alternative. */
! 4596: if (*cc == OP_KETRPOS)
! 4597: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4598: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr);
! 4599: }
! 4600: else
! 4601: {
! 4602: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 4603: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_w));
! 4604: }
! 4605: }
! 4606:
! 4607: if (*cc == OP_KETRPOS)
! 4608: break;
! 4609: ccbegin = cc + 1 + LINK_SIZE;
! 4610: }
! 4611:
! 4612: fallback->topfallbacks = NULL;
! 4613: if (!zero)
! 4614: {
! 4615: if (framesize < 0)
! 4616: add_jump(compiler, &fallback->topfallbacks, CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0));
! 4617: else /* TMP2 is set to [localptr] above. */
! 4618: add_jump(compiler, &fallback->topfallbacks, CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(TMP2), (stacksize - 1) * sizeof(sljit_w), SLJIT_IMM, 0));
! 4619: }
! 4620:
! 4621: /* None of them matched. */
! 4622: set_jumps(emptymatch, LABEL());
! 4623: decrease_call_count(common);
! 4624: return cc + 1 + LINK_SIZE;
! 4625: }
! 4626:
! 4627: static SLJIT_INLINE uschar *get_iterator_parameters(compiler_common *common, uschar *cc, uschar *opcode, uschar *type, int *arg1, int *arg2, uschar **end)
! 4628: {
! 4629: int class_len;
! 4630:
! 4631: *opcode = *cc;
! 4632: if (*opcode >= OP_STAR && *opcode <= OP_POSUPTO)
! 4633: {
! 4634: cc++;
! 4635: *type = OP_CHAR;
! 4636: }
! 4637: else if (*opcode >= OP_STARI && *opcode <= OP_POSUPTOI)
! 4638: {
! 4639: cc++;
! 4640: *type = OP_CHARI;
! 4641: *opcode -= OP_STARI - OP_STAR;
! 4642: }
! 4643: else if (*opcode >= OP_NOTSTAR && *opcode <= OP_NOTPOSUPTO)
! 4644: {
! 4645: cc++;
! 4646: *type = OP_NOT;
! 4647: *opcode -= OP_NOTSTAR - OP_STAR;
! 4648: }
! 4649: else if (*opcode >= OP_NOTSTARI && *opcode <= OP_NOTPOSUPTOI)
! 4650: {
! 4651: cc++;
! 4652: *type = OP_NOTI;
! 4653: *opcode -= OP_NOTSTARI - OP_STAR;
! 4654: }
! 4655: else if (*opcode >= OP_TYPESTAR && *opcode <= OP_TYPEPOSUPTO)
! 4656: {
! 4657: cc++;
! 4658: *opcode -= OP_TYPESTAR - OP_STAR;
! 4659: *type = 0;
! 4660: }
! 4661: else
! 4662: {
! 4663: SLJIT_ASSERT(*opcode >= OP_CLASS || *opcode <= OP_XCLASS);
! 4664: *type = *opcode;
! 4665: cc++;
! 4666: class_len = (*type < OP_XCLASS) ? 33 : GET(cc, 0);
! 4667: *opcode = cc[class_len - 1];
! 4668: if (*opcode >= OP_CRSTAR && *opcode <= OP_CRMINQUERY)
! 4669: {
! 4670: *opcode -= OP_CRSTAR - OP_STAR;
! 4671: if (end != NULL)
! 4672: *end = cc + class_len;
! 4673: }
! 4674: else
! 4675: {
! 4676: SLJIT_ASSERT(*opcode == OP_CRRANGE || *opcode == OP_CRMINRANGE);
! 4677: *arg1 = GET2(cc, (class_len + 2));
! 4678: *arg2 = GET2(cc, class_len);
! 4679:
! 4680: if (*arg2 == 0)
! 4681: {
! 4682: SLJIT_ASSERT(*arg1 != 0);
! 4683: *opcode = (*opcode == OP_CRRANGE) ? OP_UPTO : OP_MINUPTO;
! 4684: }
! 4685: if (*arg1 == *arg2)
! 4686: *opcode = OP_EXACT;
! 4687:
! 4688: if (end != NULL)
! 4689: *end = cc + class_len + 4;
! 4690: }
! 4691: return cc;
! 4692: }
! 4693:
! 4694: if (*opcode == OP_UPTO || *opcode == OP_MINUPTO || *opcode == OP_EXACT || *opcode == OP_POSUPTO)
! 4695: {
! 4696: *arg1 = GET2(cc, 0);
! 4697: cc += 2;
! 4698: }
! 4699:
! 4700: if (*type == 0)
! 4701: {
! 4702: *type = *cc;
! 4703: if (end != NULL)
! 4704: *end = next_opcode(common, cc);
! 4705: cc++;
! 4706: return cc;
! 4707: }
! 4708:
! 4709: if (end != NULL)
! 4710: {
! 4711: *end = cc + 1;
! 4712: #ifdef SUPPORT_UTF8
! 4713: if (common->utf8 && *cc >= 0xc0) *end += _pcre_utf8_table4[*cc & 0x3f];
! 4714: #endif
! 4715: }
! 4716: return cc;
! 4717: }
! 4718:
! 4719: static uschar *compile_iterator_hotpath(compiler_common *common, uschar *cc, fallback_common *parent)
! 4720: {
! 4721: DEFINE_COMPILER;
! 4722: fallback_common *fallback;
! 4723: uschar opcode;
! 4724: uschar type;
! 4725: int arg1 = -1, arg2 = -1;
! 4726: uschar* end;
! 4727: jump_list *nomatch = NULL;
! 4728: struct sljit_jump *jump = NULL;
! 4729: struct sljit_label *label;
! 4730:
! 4731: PUSH_FALLBACK(sizeof(iterator_fallback), cc, NULL);
! 4732:
! 4733: cc = get_iterator_parameters(common, cc, &opcode, &type, &arg1, &arg2, &end);
! 4734:
! 4735: switch(opcode)
! 4736: {
! 4737: case OP_STAR:
! 4738: case OP_PLUS:
! 4739: case OP_UPTO:
! 4740: case OP_CRRANGE:
! 4741: if (type == OP_ANYNL || type == OP_EXTUNI)
! 4742: {
! 4743: if (opcode == OP_STAR || opcode == OP_UPTO)
! 4744: {
! 4745: allocate_stack(common, 2);
! 4746: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4747: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
! 4748: }
! 4749: else
! 4750: {
! 4751: allocate_stack(common, 1);
! 4752: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 4753: }
! 4754: if (opcode == OP_UPTO || opcode == OP_CRRANGE)
! 4755: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 0);
! 4756:
! 4757: label = LABEL();
! 4758: compile_char1_hotpath(common, type, cc, &fallback->topfallbacks);
! 4759: if (opcode == OP_UPTO || opcode == OP_CRRANGE)
! 4760: {
! 4761: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0);
! 4762: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 4763: if (opcode == OP_CRRANGE && arg2 > 0)
! 4764: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg2, label);
! 4765: if (opcode == OP_UPTO || (opcode == OP_CRRANGE && arg1 > 0))
! 4766: jump = CMP(SLJIT_C_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, arg1);
! 4767: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, TMP1, 0);
! 4768: }
! 4769:
! 4770: allocate_stack(common, 1);
! 4771: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4772: JUMPTO(SLJIT_JUMP, label);
! 4773: if (jump != NULL)
! 4774: JUMPHERE(jump);
! 4775: }
! 4776: else
! 4777: {
! 4778: allocate_stack(common, 2);
! 4779: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4780: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1);
! 4781: label = LABEL();
! 4782: compile_char1_hotpath(common, type, cc, &nomatch);
! 4783: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4784: if (opcode <= OP_PLUS || (opcode == OP_CRRANGE && arg1 == 0))
! 4785: {
! 4786: OP2(SLJIT_ADD, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1);
! 4787: JUMPTO(SLJIT_JUMP, label);
! 4788: }
! 4789: else
! 4790: {
! 4791: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 4792: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 4793: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
! 4794: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg1 + 1, label);
! 4795: }
! 4796: set_jumps(nomatch, LABEL());
! 4797: if (opcode == OP_PLUS || opcode == OP_CRRANGE)
! 4798: add_jump(compiler, &fallback->topfallbacks,
! 4799: CMP(SLJIT_C_LESS, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, opcode == OP_PLUS ? 2 : arg2 + 1));
! 4800: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 4801: }
! 4802: FALLBACK_AS(iterator_fallback)->hotpath = LABEL();
! 4803: break;
! 4804:
! 4805: case OP_MINSTAR:
! 4806: case OP_MINPLUS:
! 4807: allocate_stack(common, 1);
! 4808: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4809: if (opcode == OP_MINPLUS)
! 4810: add_jump(compiler, &fallback->topfallbacks, JUMP(SLJIT_JUMP));
! 4811: FALLBACK_AS(iterator_fallback)->hotpath = LABEL();
! 4812: break;
! 4813:
! 4814: case OP_MINUPTO:
! 4815: case OP_CRMINRANGE:
! 4816: allocate_stack(common, 2);
! 4817: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4818: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1);
! 4819: if (opcode == OP_CRMINRANGE)
! 4820: add_jump(compiler, &fallback->topfallbacks, JUMP(SLJIT_JUMP));
! 4821: FALLBACK_AS(iterator_fallback)->hotpath = LABEL();
! 4822: break;
! 4823:
! 4824: case OP_QUERY:
! 4825: case OP_MINQUERY:
! 4826: allocate_stack(common, 1);
! 4827: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 4828: if (opcode == OP_QUERY)
! 4829: compile_char1_hotpath(common, type, cc, &fallback->topfallbacks);
! 4830: FALLBACK_AS(iterator_fallback)->hotpath = LABEL();
! 4831: break;
! 4832:
! 4833: case OP_EXACT:
! 4834: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 1);
! 4835: label = LABEL();
! 4836: compile_char1_hotpath(common, type, cc, &fallback->topfallbacks);
! 4837: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0);
! 4838: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 4839: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, TMP1, 0);
! 4840: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg1 + 1, label);
! 4841: break;
! 4842:
! 4843: case OP_POSSTAR:
! 4844: case OP_POSPLUS:
! 4845: case OP_POSUPTO:
! 4846: if (opcode != OP_POSSTAR)
! 4847: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 1);
! 4848: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STR_PTR, 0);
! 4849: label = LABEL();
! 4850: compile_char1_hotpath(common, type, cc, &nomatch);
! 4851: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STR_PTR, 0);
! 4852: if (opcode != OP_POSUPTO)
! 4853: {
! 4854: if (opcode == OP_POSPLUS)
! 4855: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 2);
! 4856: JUMPTO(SLJIT_JUMP, label);
! 4857: }
! 4858: else
! 4859: {
! 4860: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0);
! 4861: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 4862: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, TMP1, 0);
! 4863: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg1 + 1, label);
! 4864: }
! 4865: set_jumps(nomatch, LABEL());
! 4866: if (opcode == OP_POSPLUS)
! 4867: add_jump(compiler, &fallback->topfallbacks, CMP(SLJIT_C_LESS, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 2));
! 4868: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1);
! 4869: break;
! 4870:
! 4871: case OP_POSQUERY:
! 4872: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STR_PTR, 0);
! 4873: compile_char1_hotpath(common, type, cc, &nomatch);
! 4874: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STR_PTR, 0);
! 4875: set_jumps(nomatch, LABEL());
! 4876: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1);
! 4877: break;
! 4878:
! 4879: default:
! 4880: SLJIT_ASSERT_STOP();
! 4881: break;
! 4882: }
! 4883:
! 4884: decrease_call_count(common);
! 4885: return end;
! 4886: }
! 4887:
! 4888: static SLJIT_INLINE uschar *compile_fail_accept_hotpath(compiler_common *common, uschar *cc, fallback_common *parent)
! 4889: {
! 4890: DEFINE_COMPILER;
! 4891: fallback_common *fallback;
! 4892:
! 4893: PUSH_FALLBACK(sizeof(bracket_fallback), cc, NULL);
! 4894:
! 4895: if (*cc == OP_FAIL)
! 4896: {
! 4897: add_jump(compiler, &fallback->topfallbacks, JUMP(SLJIT_JUMP));
! 4898: return cc + 1;
! 4899: }
! 4900:
! 4901: if (*cc == OP_ASSERT_ACCEPT || common->currententry != NULL)
! 4902: {
! 4903: /* No need to check notempty conditions. */
! 4904: if (common->acceptlabel == NULL)
! 4905: add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP));
! 4906: else
! 4907: JUMPTO(SLJIT_JUMP, common->acceptlabel);
! 4908: return cc + 1;
! 4909: }
! 4910:
! 4911: if (common->acceptlabel == NULL)
! 4912: add_jump(compiler, &common->accept, CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0)));
! 4913: else
! 4914: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), common->acceptlabel);
! 4915: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 4916: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty));
! 4917: add_jump(compiler, &fallback->topfallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
! 4918: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart));
! 4919: if (common->acceptlabel == NULL)
! 4920: add_jump(compiler, &common->accept, CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, 0));
! 4921: else
! 4922: CMPTO(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, 0, common->acceptlabel);
! 4923: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
! 4924: if (common->acceptlabel == NULL)
! 4925: add_jump(compiler, &common->accept, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0));
! 4926: else
! 4927: CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0, common->acceptlabel);
! 4928: add_jump(compiler, &fallback->topfallbacks, JUMP(SLJIT_JUMP));
! 4929: return cc + 1;
! 4930: }
! 4931:
! 4932: static SLJIT_INLINE uschar *compile_close_hotpath(compiler_common *common, uschar *cc)
! 4933: {
! 4934: DEFINE_COMPILER;
! 4935: int offset = GET2(cc, 1);
! 4936:
! 4937: /* Data will be discarded anyway... */
! 4938: if (common->currententry != NULL)
! 4939: return cc + 3;
! 4940:
! 4941: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR_PRIV(offset));
! 4942: offset <<= 1;
! 4943: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0);
! 4944: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
! 4945: return cc + 3;
! 4946: }
! 4947:
! 4948: static void compile_hotpath(compiler_common *common, uschar *cc, uschar *ccend, fallback_common *parent)
! 4949: {
! 4950: DEFINE_COMPILER;
! 4951: fallback_common *fallback;
! 4952:
! 4953: while (cc < ccend)
! 4954: {
! 4955: switch(*cc)
! 4956: {
! 4957: case OP_SOD:
! 4958: case OP_SOM:
! 4959: case OP_NOT_WORD_BOUNDARY:
! 4960: case OP_WORD_BOUNDARY:
! 4961: case OP_NOT_DIGIT:
! 4962: case OP_DIGIT:
! 4963: case OP_NOT_WHITESPACE:
! 4964: case OP_WHITESPACE:
! 4965: case OP_NOT_WORDCHAR:
! 4966: case OP_WORDCHAR:
! 4967: case OP_ANY:
! 4968: case OP_ALLANY:
! 4969: case OP_ANYBYTE:
! 4970: case OP_NOTPROP:
! 4971: case OP_PROP:
! 4972: case OP_ANYNL:
! 4973: case OP_NOT_HSPACE:
! 4974: case OP_HSPACE:
! 4975: case OP_NOT_VSPACE:
! 4976: case OP_VSPACE:
! 4977: case OP_EXTUNI:
! 4978: case OP_EODN:
! 4979: case OP_EOD:
! 4980: case OP_CIRC:
! 4981: case OP_CIRCM:
! 4982: case OP_DOLL:
! 4983: case OP_DOLLM:
! 4984: case OP_NOT:
! 4985: case OP_NOTI:
! 4986: case OP_REVERSE:
! 4987: cc = compile_char1_hotpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextfallbacks : &parent->topfallbacks);
! 4988: break;
! 4989:
! 4990: case OP_SET_SOM:
! 4991: PUSH_FALLBACK_NOVALUE(sizeof(fallback_common), cc);
! 4992: allocate_stack(common, 1);
! 4993: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0));
! 4994: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), STR_PTR, 0);
! 4995: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
! 4996: cc++;
! 4997: break;
! 4998:
! 4999: case OP_CHAR:
! 5000: case OP_CHARI:
! 5001: cc = compile_charn_hotpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextfallbacks : &parent->topfallbacks);
! 5002: break;
! 5003:
! 5004: case OP_STAR:
! 5005: case OP_MINSTAR:
! 5006: case OP_PLUS:
! 5007: case OP_MINPLUS:
! 5008: case OP_QUERY:
! 5009: case OP_MINQUERY:
! 5010: case OP_UPTO:
! 5011: case OP_MINUPTO:
! 5012: case OP_EXACT:
! 5013: case OP_POSSTAR:
! 5014: case OP_POSPLUS:
! 5015: case OP_POSQUERY:
! 5016: case OP_POSUPTO:
! 5017: case OP_STARI:
! 5018: case OP_MINSTARI:
! 5019: case OP_PLUSI:
! 5020: case OP_MINPLUSI:
! 5021: case OP_QUERYI:
! 5022: case OP_MINQUERYI:
! 5023: case OP_UPTOI:
! 5024: case OP_MINUPTOI:
! 5025: case OP_EXACTI:
! 5026: case OP_POSSTARI:
! 5027: case OP_POSPLUSI:
! 5028: case OP_POSQUERYI:
! 5029: case OP_POSUPTOI:
! 5030: case OP_NOTSTAR:
! 5031: case OP_NOTMINSTAR:
! 5032: case OP_NOTPLUS:
! 5033: case OP_NOTMINPLUS:
! 5034: case OP_NOTQUERY:
! 5035: case OP_NOTMINQUERY:
! 5036: case OP_NOTUPTO:
! 5037: case OP_NOTMINUPTO:
! 5038: case OP_NOTEXACT:
! 5039: case OP_NOTPOSSTAR:
! 5040: case OP_NOTPOSPLUS:
! 5041: case OP_NOTPOSQUERY:
! 5042: case OP_NOTPOSUPTO:
! 5043: case OP_NOTSTARI:
! 5044: case OP_NOTMINSTARI:
! 5045: case OP_NOTPLUSI:
! 5046: case OP_NOTMINPLUSI:
! 5047: case OP_NOTQUERYI:
! 5048: case OP_NOTMINQUERYI:
! 5049: case OP_NOTUPTOI:
! 5050: case OP_NOTMINUPTOI:
! 5051: case OP_NOTEXACTI:
! 5052: case OP_NOTPOSSTARI:
! 5053: case OP_NOTPOSPLUSI:
! 5054: case OP_NOTPOSQUERYI:
! 5055: case OP_NOTPOSUPTOI:
! 5056: case OP_TYPESTAR:
! 5057: case OP_TYPEMINSTAR:
! 5058: case OP_TYPEPLUS:
! 5059: case OP_TYPEMINPLUS:
! 5060: case OP_TYPEQUERY:
! 5061: case OP_TYPEMINQUERY:
! 5062: case OP_TYPEUPTO:
! 5063: case OP_TYPEMINUPTO:
! 5064: case OP_TYPEEXACT:
! 5065: case OP_TYPEPOSSTAR:
! 5066: case OP_TYPEPOSPLUS:
! 5067: case OP_TYPEPOSQUERY:
! 5068: case OP_TYPEPOSUPTO:
! 5069: cc = compile_iterator_hotpath(common, cc, parent);
! 5070: break;
! 5071:
! 5072: case OP_CLASS:
! 5073: case OP_NCLASS:
! 5074: if (cc[33] >= OP_CRSTAR && cc[33] <= OP_CRMINRANGE)
! 5075: cc = compile_iterator_hotpath(common, cc, parent);
! 5076: else
! 5077: cc = compile_char1_hotpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextfallbacks : &parent->topfallbacks);
! 5078: break;
! 5079:
! 5080: #ifdef SUPPORT_UTF8
! 5081: case OP_XCLASS:
! 5082: if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= OP_CRMINRANGE)
! 5083: cc = compile_iterator_hotpath(common, cc, parent);
! 5084: else
! 5085: cc = compile_char1_hotpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextfallbacks : &parent->topfallbacks);
! 5086: break;
! 5087: #endif
! 5088:
! 5089: case OP_REF:
! 5090: case OP_REFI:
! 5091: if (cc[3] >= OP_CRSTAR && cc[3] <= OP_CRMINRANGE)
! 5092: cc = compile_ref_iterator_hotpath(common, cc, parent);
! 5093: else
! 5094: cc = compile_ref_hotpath(common, cc, parent->top != NULL ? &parent->top->nextfallbacks : &parent->topfallbacks, TRUE, FALSE);
! 5095: break;
! 5096:
! 5097: case OP_RECURSE:
! 5098: cc = compile_recurse_hotpath(common, cc, parent);
! 5099: break;
! 5100:
! 5101: case OP_ASSERT:
! 5102: case OP_ASSERT_NOT:
! 5103: case OP_ASSERTBACK:
! 5104: case OP_ASSERTBACK_NOT:
! 5105: PUSH_FALLBACK_NOVALUE(sizeof(assert_fallback), cc);
! 5106: cc = compile_assert_hotpath(common, cc, FALLBACK_AS(assert_fallback), FALSE);
! 5107: break;
! 5108:
! 5109: case OP_BRAMINZERO:
! 5110: PUSH_FALLBACK_NOVALUE(sizeof(braminzero_fallback), cc);
! 5111: cc = bracketend(cc + 1);
! 5112: if (*(cc - 1 - LINK_SIZE) != OP_KETRMIN)
! 5113: {
! 5114: allocate_stack(common, 1);
! 5115: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 5116: }
! 5117: else
! 5118: {
! 5119: allocate_stack(common, 2);
! 5120: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 5121: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_PTR, 0);
! 5122: }
! 5123: FALLBACK_AS(braminzero_fallback)->hotpath = LABEL();
! 5124: if (cc[1] > OP_ASSERTBACK_NOT)
! 5125: decrease_call_count(common);
! 5126: break;
! 5127:
! 5128: case OP_ONCE:
! 5129: case OP_ONCE_NC:
! 5130: case OP_BRA:
! 5131: case OP_CBRA:
! 5132: case OP_COND:
! 5133: case OP_SBRA:
! 5134: case OP_SCBRA:
! 5135: case OP_SCOND:
! 5136: cc = compile_bracket_hotpath(common, cc, parent);
! 5137: break;
! 5138:
! 5139: case OP_BRAZERO:
! 5140: if (cc[1] > OP_ASSERTBACK_NOT)
! 5141: cc = compile_bracket_hotpath(common, cc, parent);
! 5142: else
! 5143: {
! 5144: PUSH_FALLBACK_NOVALUE(sizeof(assert_fallback), cc);
! 5145: cc = compile_assert_hotpath(common, cc, FALLBACK_AS(assert_fallback), FALSE);
! 5146: }
! 5147: break;
! 5148:
! 5149: case OP_BRAPOS:
! 5150: case OP_CBRAPOS:
! 5151: case OP_SBRAPOS:
! 5152: case OP_SCBRAPOS:
! 5153: case OP_BRAPOSZERO:
! 5154: cc = compile_bracketpos_hotpath(common, cc, parent);
! 5155: break;
! 5156:
! 5157: case OP_FAIL:
! 5158: case OP_ACCEPT:
! 5159: case OP_ASSERT_ACCEPT:
! 5160: cc = compile_fail_accept_hotpath(common, cc, parent);
! 5161: break;
! 5162:
! 5163: case OP_CLOSE:
! 5164: cc = compile_close_hotpath(common, cc);
! 5165: break;
! 5166:
! 5167: case OP_SKIPZERO:
! 5168: cc = bracketend(cc + 1);
! 5169: break;
! 5170:
! 5171: default:
! 5172: SLJIT_ASSERT_STOP();
! 5173: return;
! 5174: }
! 5175: if (cc == NULL)
! 5176: return;
! 5177: }
! 5178: SLJIT_ASSERT(cc == ccend);
! 5179: }
! 5180:
! 5181: #undef PUSH_FALLBACK
! 5182: #undef PUSH_FALLBACK_NOVALUE
! 5183: #undef FALLBACK_AS
! 5184:
! 5185: #define COMPILE_FALLBACKPATH(current) \
! 5186: do \
! 5187: { \
! 5188: compile_fallbackpath(common, (current)); \
! 5189: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \
! 5190: return; \
! 5191: } \
! 5192: while (0)
! 5193:
! 5194: #define CURRENT_AS(type) ((type*)current)
! 5195:
! 5196: static void compile_iterator_fallbackpath(compiler_common *common, struct fallback_common *current)
! 5197: {
! 5198: DEFINE_COMPILER;
! 5199: uschar *cc = current->cc;
! 5200: uschar opcode;
! 5201: uschar type;
! 5202: int arg1 = -1, arg2 = -1;
! 5203: struct sljit_label *label = NULL;
! 5204: struct sljit_jump *jump = NULL;
! 5205:
! 5206: cc = get_iterator_parameters(common, cc, &opcode, &type, &arg1, &arg2, NULL);
! 5207:
! 5208: switch(opcode)
! 5209: {
! 5210: case OP_STAR:
! 5211: case OP_PLUS:
! 5212: case OP_UPTO:
! 5213: case OP_CRRANGE:
! 5214: if (type == OP_ANYNL || type == OP_EXTUNI)
! 5215: {
! 5216: set_jumps(current->topfallbacks, LABEL());
! 5217: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5218: free_stack(common, 1);
! 5219: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_fallback)->hotpath);
! 5220: }
! 5221: else
! 5222: {
! 5223: if (opcode == OP_STAR || opcode == OP_UPTO)
! 5224: arg2 = 0;
! 5225: else if (opcode == OP_PLUS)
! 5226: arg2 = 1;
! 5227: jump = CMP(SLJIT_C_LESS_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, arg2 + 1);
! 5228: OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1);
! 5229: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5230: skip_char_back(common);
! 5231: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 5232: JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_fallback)->hotpath);
! 5233: if (opcode == OP_PLUS || opcode == OP_CRRANGE)
! 5234: set_jumps(current->topfallbacks, LABEL());
! 5235: JUMPHERE(jump);
! 5236: free_stack(common, 2);
! 5237: }
! 5238: break;
! 5239:
! 5240: case OP_MINSTAR:
! 5241: case OP_MINPLUS:
! 5242: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5243: if (opcode == OP_MINPLUS)
! 5244: {
! 5245: set_jumps(current->topfallbacks, LABEL());
! 5246: current->topfallbacks = NULL;
! 5247: }
! 5248: compile_char1_hotpath(common, type, cc, ¤t->topfallbacks);
! 5249: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 5250: JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_fallback)->hotpath);
! 5251: set_jumps(current->topfallbacks, LABEL());
! 5252: free_stack(common, 1);
! 5253: break;
! 5254:
! 5255: case OP_MINUPTO:
! 5256: case OP_CRMINRANGE:
! 5257: if (opcode == OP_CRMINRANGE)
! 5258: {
! 5259: set_jumps(current->topfallbacks, LABEL());
! 5260: current->topfallbacks = NULL;
! 5261: label = LABEL();
! 5262: }
! 5263: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5264: compile_char1_hotpath(common, type, cc, ¤t->topfallbacks);
! 5265:
! 5266: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 5267: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 5268: OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
! 5269: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
! 5270:
! 5271: if (opcode == OP_CRMINRANGE)
! 5272: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg2 + 1, label);
! 5273:
! 5274: if (opcode == OP_CRMINRANGE && arg1 == 0)
! 5275: JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_fallback)->hotpath);
! 5276: else
! 5277: CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg1 + 2, CURRENT_AS(iterator_fallback)->hotpath);
! 5278:
! 5279: set_jumps(current->topfallbacks, LABEL());
! 5280: free_stack(common, 2);
! 5281: break;
! 5282:
! 5283: case OP_QUERY:
! 5284: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5285: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 5286: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_fallback)->hotpath);
! 5287: jump = JUMP(SLJIT_JUMP);
! 5288: set_jumps(current->topfallbacks, LABEL());
! 5289: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5290: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 5291: JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_fallback)->hotpath);
! 5292: JUMPHERE(jump);
! 5293: free_stack(common, 1);
! 5294: break;
! 5295:
! 5296: case OP_MINQUERY:
! 5297: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5298: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 5299: jump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
! 5300: compile_char1_hotpath(common, type, cc, ¤t->topfallbacks);
! 5301: JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_fallback)->hotpath);
! 5302: set_jumps(current->topfallbacks, LABEL());
! 5303: JUMPHERE(jump);
! 5304: free_stack(common, 1);
! 5305: break;
! 5306:
! 5307: case OP_EXACT:
! 5308: case OP_POSPLUS:
! 5309: set_jumps(current->topfallbacks, LABEL());
! 5310: break;
! 5311:
! 5312: case OP_POSSTAR:
! 5313: case OP_POSQUERY:
! 5314: case OP_POSUPTO:
! 5315: break;
! 5316:
! 5317: default:
! 5318: SLJIT_ASSERT_STOP();
! 5319: break;
! 5320: }
! 5321: }
! 5322:
! 5323: static void compile_ref_iterator_fallbackpath(compiler_common *common, struct fallback_common *current)
! 5324: {
! 5325: DEFINE_COMPILER;
! 5326: uschar *cc = current->cc;
! 5327: uschar type;
! 5328:
! 5329: type = cc[3];
! 5330: if ((type & 0x1) == 0)
! 5331: {
! 5332: set_jumps(current->topfallbacks, LABEL());
! 5333: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5334: free_stack(common, 1);
! 5335: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_fallback)->hotpath);
! 5336: return;
! 5337: }
! 5338:
! 5339: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5340: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_fallback)->hotpath);
! 5341: set_jumps(current->topfallbacks, LABEL());
! 5342: free_stack(common, 2);
! 5343: }
! 5344:
! 5345: static void compile_recurse_fallbackpath(compiler_common *common, struct fallback_common *current)
! 5346: {
! 5347: DEFINE_COMPILER;
! 5348:
! 5349: set_jumps(current->topfallbacks, LABEL());
! 5350: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5351: free_stack(common, 1);
! 5352: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), TMP2, 0);
! 5353: }
! 5354:
! 5355: static void compile_assert_fallbackpath(compiler_common *common, struct fallback_common *current)
! 5356: {
! 5357: DEFINE_COMPILER;
! 5358: uschar *cc = current->cc;
! 5359: uschar bra = OP_BRA;
! 5360: struct sljit_jump *brajump = NULL;
! 5361:
! 5362: SLJIT_ASSERT(*cc != OP_BRAMINZERO);
! 5363: if (*cc == OP_BRAZERO)
! 5364: {
! 5365: bra = *cc;
! 5366: cc++;
! 5367: }
! 5368:
! 5369: if (bra == OP_BRAZERO)
! 5370: {
! 5371: SLJIT_ASSERT(current->topfallbacks == NULL);
! 5372: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5373: }
! 5374:
! 5375: if (CURRENT_AS(assert_fallback)->framesize < 0)
! 5376: {
! 5377: set_jumps(current->topfallbacks, LABEL());
! 5378:
! 5379: if (bra == OP_BRAZERO)
! 5380: {
! 5381: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 5382: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_fallback)->hotpath);
! 5383: free_stack(common, 1);
! 5384: }
! 5385: return;
! 5386: }
! 5387:
! 5388: if (bra == OP_BRAZERO)
! 5389: {
! 5390: if (*cc == OP_ASSERT_NOT || *cc == OP_ASSERTBACK_NOT)
! 5391: {
! 5392: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 5393: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_fallback)->hotpath);
! 5394: free_stack(common, 1);
! 5395: return;
! 5396: }
! 5397: free_stack(common, 1);
! 5398: brajump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
! 5399: }
! 5400:
! 5401: if (*cc == OP_ASSERT || *cc == OP_ASSERTBACK)
! 5402: {
! 5403: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_fallback)->localptr);
! 5404: add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
! 5405: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_fallback)->localptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(assert_fallback)->framesize * sizeof(sljit_w));
! 5406:
! 5407: set_jumps(current->topfallbacks, LABEL());
! 5408: }
! 5409: else
! 5410: set_jumps(current->topfallbacks, LABEL());
! 5411:
! 5412: if (bra == OP_BRAZERO)
! 5413: {
! 5414: /* We know there is enough place on the stack. */
! 5415: OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w));
! 5416: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
! 5417: JUMPTO(SLJIT_JUMP, CURRENT_AS(assert_fallback)->hotpath);
! 5418: JUMPHERE(brajump);
! 5419: }
! 5420: }
! 5421:
! 5422: static void compile_bracket_fallbackpath(compiler_common *common, struct fallback_common *current)
! 5423: {
! 5424: DEFINE_COMPILER;
! 5425: int opcode;
! 5426: int offset = 0;
! 5427: int localptr = CURRENT_AS(bracket_fallback)->localptr;
! 5428: int stacksize;
! 5429: int count;
! 5430: uschar *cc = current->cc;
! 5431: uschar *ccbegin;
! 5432: uschar *ccprev;
! 5433: jump_list *jumplist = NULL;
! 5434: jump_list *jumplistitem = NULL;
! 5435: uschar bra = OP_BRA;
! 5436: uschar ket;
! 5437: assert_fallback *assert;
! 5438: BOOL has_alternatives;
! 5439: struct sljit_jump *brazero = NULL;
! 5440: struct sljit_jump *once = NULL;
! 5441: struct sljit_jump *cond = NULL;
! 5442: struct sljit_label *rminlabel = NULL;
! 5443:
! 5444: if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
! 5445: {
! 5446: bra = *cc;
! 5447: cc++;
! 5448: }
! 5449:
! 5450: opcode = *cc;
! 5451: ccbegin = cc;
! 5452: ket = *(bracketend(ccbegin) - 1 - LINK_SIZE);
! 5453: cc += GET(cc, 1);
! 5454: has_alternatives = *cc == OP_ALT;
! 5455: if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
! 5456: has_alternatives = (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT) || CURRENT_AS(bracket_fallback)->u.condfailed != NULL;
! 5457: if (opcode == OP_CBRA || opcode == OP_SCBRA)
! 5458: offset = (GET2(ccbegin, 1 + LINK_SIZE)) << 1;
! 5459: if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN))
! 5460: opcode = OP_SCOND;
! 5461: if (SLJIT_UNLIKELY(opcode == OP_ONCE_NC))
! 5462: opcode = OP_ONCE;
! 5463:
! 5464: if (ket == OP_KETRMAX)
! 5465: {
! 5466: if (bra != OP_BRAZERO)
! 5467: free_stack(common, 1);
! 5468: else
! 5469: {
! 5470: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5471: free_stack(common, 1);
! 5472: brazero = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, 0);
! 5473: }
! 5474: }
! 5475: else if (ket == OP_KETRMIN)
! 5476: {
! 5477: if (bra != OP_BRAMINZERO)
! 5478: {
! 5479: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5480: if (opcode >= OP_SBRA || opcode == OP_ONCE)
! 5481: {
! 5482: /* Checking zero-length iteration. */
! 5483: if (opcode != OP_ONCE || CURRENT_AS(bracket_fallback)->u.framesize < 0)
! 5484: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, CURRENT_AS(bracket_fallback)->recursivehotpath);
! 5485: else
! 5486: {
! 5487: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 5488: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (CURRENT_AS(bracket_fallback)->u.framesize + 1) * sizeof(sljit_w), CURRENT_AS(bracket_fallback)->recursivehotpath);
! 5489: }
! 5490: if (opcode != OP_ONCE)
! 5491: free_stack(common, 1);
! 5492: }
! 5493: else
! 5494: JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_fallback)->recursivehotpath);
! 5495: }
! 5496: rminlabel = LABEL();
! 5497: }
! 5498: else if (bra == OP_BRAZERO)
! 5499: {
! 5500: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5501: free_stack(common, 1);
! 5502: brazero = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0);
! 5503: }
! 5504:
! 5505: if (SLJIT_UNLIKELY(opcode == OP_ONCE))
! 5506: {
! 5507: if (CURRENT_AS(bracket_fallback)->u.framesize >= 0)
! 5508: {
! 5509: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 5510: add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
! 5511: }
! 5512: once = JUMP(SLJIT_JUMP);
! 5513: }
! 5514: else if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
! 5515: {
! 5516: if (has_alternatives)
! 5517: {
! 5518: /* Always exactly one alternative. */
! 5519: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5520: free_stack(common, 1);
! 5521:
! 5522: jumplistitem = sljit_alloc_memory(compiler, sizeof(jump_list));
! 5523: if (SLJIT_UNLIKELY(!jumplistitem))
! 5524: return;
! 5525: jumplist = jumplistitem;
! 5526: jumplistitem->next = NULL;
! 5527: jumplistitem->jump = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, 1);
! 5528: }
! 5529: }
! 5530: else if (*cc == OP_ALT)
! 5531: {
! 5532: /* Build a jump list. Get the last successfully matched branch index. */
! 5533: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5534: free_stack(common, 1);
! 5535: count = 1;
! 5536: do
! 5537: {
! 5538: /* Append as the last item. */
! 5539: if (jumplist != NULL)
! 5540: {
! 5541: jumplistitem->next = sljit_alloc_memory(compiler, sizeof(jump_list));
! 5542: jumplistitem = jumplistitem->next;
! 5543: }
! 5544: else
! 5545: {
! 5546: jumplistitem = sljit_alloc_memory(compiler, sizeof(jump_list));
! 5547: jumplist = jumplistitem;
! 5548: }
! 5549:
! 5550: if (SLJIT_UNLIKELY(!jumplistitem))
! 5551: return;
! 5552:
! 5553: jumplistitem->next = NULL;
! 5554: jumplistitem->jump = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, count++);
! 5555: cc += GET(cc, 1);
! 5556: }
! 5557: while (*cc == OP_ALT);
! 5558:
! 5559: cc = ccbegin + GET(ccbegin, 1);
! 5560: }
! 5561:
! 5562: COMPILE_FALLBACKPATH(current->top);
! 5563: if (current->topfallbacks)
! 5564: set_jumps(current->topfallbacks, LABEL());
! 5565:
! 5566: if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
! 5567: {
! 5568: /* Conditional block always has at most one alternative. */
! 5569: if (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT)
! 5570: {
! 5571: SLJIT_ASSERT(has_alternatives);
! 5572: assert = CURRENT_AS(bracket_fallback)->u.assert;
! 5573: if (assert->framesize >= 0 && (ccbegin[1 + LINK_SIZE] == OP_ASSERT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK))
! 5574: {
! 5575: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->localptr);
! 5576: add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
! 5577: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->localptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_w));
! 5578: }
! 5579: cond = JUMP(SLJIT_JUMP);
! 5580: set_jumps(CURRENT_AS(bracket_fallback)->u.assert->condfailed, LABEL());
! 5581: }
! 5582: else if (CURRENT_AS(bracket_fallback)->u.condfailed != NULL)
! 5583: {
! 5584: SLJIT_ASSERT(has_alternatives);
! 5585: cond = JUMP(SLJIT_JUMP);
! 5586: set_jumps(CURRENT_AS(bracket_fallback)->u.condfailed, LABEL());
! 5587: }
! 5588: else
! 5589: SLJIT_ASSERT(!has_alternatives);
! 5590: }
! 5591:
! 5592: if (has_alternatives)
! 5593: {
! 5594: count = 1;
! 5595: do
! 5596: {
! 5597: current->top = NULL;
! 5598: current->topfallbacks = NULL;
! 5599: current->nextfallbacks = NULL;
! 5600: if (*cc == OP_ALT)
! 5601: {
! 5602: ccprev = cc + 1 + LINK_SIZE;
! 5603: cc += GET(cc, 1);
! 5604: if (opcode != OP_COND && opcode != OP_SCOND)
! 5605: {
! 5606: if (localptr != 0 && opcode != OP_ONCE)
! 5607: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 5608: else
! 5609: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5610: }
! 5611: compile_hotpath(common, ccprev, cc, current);
! 5612: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 5613: return;
! 5614: }
! 5615:
! 5616: /* Instructions after the current alternative is succesfully matched. */
! 5617: /* There is a similar code in compile_bracket_hotpath. */
! 5618: if (opcode == OP_ONCE)
! 5619: {
! 5620: if (CURRENT_AS(bracket_fallback)->u.framesize < 0)
! 5621: {
! 5622: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 5623: /* TMP2 which is set here used by OP_KETRMAX below. */
! 5624: if (ket == OP_KETRMAX)
! 5625: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), 0);
! 5626: else if (ket == OP_KETRMIN)
! 5627: {
! 5628: /* Move the STR_PTR to the localptr. */
! 5629: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), 0);
! 5630: }
! 5631: }
! 5632: else
! 5633: {
! 5634: OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (CURRENT_AS(bracket_fallback)->u.framesize + 2) * sizeof(sljit_w));
! 5635: if (ket == OP_KETRMAX)
! 5636: {
! 5637: /* TMP2 which is set here used by OP_KETRMAX below. */
! 5638: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5639: }
! 5640: }
! 5641: }
! 5642:
! 5643: stacksize = 0;
! 5644: if (opcode != OP_ONCE)
! 5645: stacksize++;
! 5646: if (ket != OP_KET || bra != OP_BRA)
! 5647: stacksize++;
! 5648:
! 5649: if (stacksize > 0) {
! 5650: if (opcode != OP_ONCE || CURRENT_AS(bracket_fallback)->u.framesize >= 0)
! 5651: allocate_stack(common, stacksize);
! 5652: else
! 5653: {
! 5654: /* We know we have place at least for one item on the top of the stack. */
! 5655: SLJIT_ASSERT(stacksize == 1);
! 5656: OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w));
! 5657: }
! 5658: }
! 5659:
! 5660: stacksize = 0;
! 5661: if (ket != OP_KET || bra != OP_BRA)
! 5662: {
! 5663: if (ket != OP_KET)
! 5664: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
! 5665: else
! 5666: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
! 5667: stacksize++;
! 5668: }
! 5669:
! 5670: if (opcode != OP_ONCE)
! 5671: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, count++);
! 5672:
! 5673: if (offset != 0)
! 5674: {
! 5675: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
! 5676: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0);
! 5677: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 0), TMP1, 0);
! 5678: }
! 5679:
! 5680: JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_fallback)->althotpath);
! 5681:
! 5682: if (opcode != OP_ONCE)
! 5683: {
! 5684: SLJIT_ASSERT(jumplist);
! 5685: JUMPHERE(jumplist->jump);
! 5686: jumplist = jumplist->next;
! 5687: }
! 5688:
! 5689: COMPILE_FALLBACKPATH(current->top);
! 5690: if (current->topfallbacks)
! 5691: set_jumps(current->topfallbacks, LABEL());
! 5692: SLJIT_ASSERT(!current->nextfallbacks);
! 5693: }
! 5694: while (*cc == OP_ALT);
! 5695: SLJIT_ASSERT(!jumplist);
! 5696:
! 5697: if (cond != NULL)
! 5698: {
! 5699: SLJIT_ASSERT(opcode == OP_COND || opcode == OP_SCOND);
! 5700: assert = CURRENT_AS(bracket_fallback)->u.assert;
! 5701: if ((ccbegin[1 + LINK_SIZE] == OP_ASSERT_NOT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK_NOT) && assert->framesize >= 0)
! 5702:
! 5703: {
! 5704: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->localptr);
! 5705: add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
! 5706: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->localptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_w));
! 5707: }
! 5708: JUMPHERE(cond);
! 5709: }
! 5710:
! 5711: /* Free the STR_PTR. */
! 5712: if (localptr == 0)
! 5713: free_stack(common, 1);
! 5714: }
! 5715:
! 5716: if (offset != 0)
! 5717: {
! 5718: /* Using both tmp register is better for instruction scheduling. */
! 5719: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5720: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 5721: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
! 5722: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP2, 0);
! 5723: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), STACK(2));
! 5724: free_stack(common, 3);
! 5725: }
! 5726: else if (opcode == OP_SBRA || opcode == OP_SCOND)
! 5727: {
! 5728: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5729: free_stack(common, 1);
! 5730: }
! 5731: else if (opcode == OP_ONCE)
! 5732: {
! 5733: cc = ccbegin + GET(ccbegin, 1);
! 5734: if (CURRENT_AS(bracket_fallback)->u.framesize >= 0)
! 5735: {
! 5736: /* Reset head and drop saved frame. */
! 5737: stacksize = (ket == OP_KETRMAX || ket == OP_KETRMIN || *cc == OP_ALT) ? 2 : 1;
! 5738: free_stack(common, CURRENT_AS(bracket_fallback)->u.framesize + stacksize);
! 5739: }
! 5740: else if (ket == OP_KETRMAX || (*cc == OP_ALT && ket != OP_KETRMIN))
! 5741: {
! 5742: /* The STR_PTR must be released. */
! 5743: free_stack(common, 1);
! 5744: }
! 5745:
! 5746: JUMPHERE(once);
! 5747: /* Restore previous localptr */
! 5748: if (CURRENT_AS(bracket_fallback)->u.framesize >= 0)
! 5749: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracket_fallback)->u.framesize * sizeof(sljit_w));
! 5750: else if (ket == OP_KETRMIN)
! 5751: {
! 5752: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 5753: /* See the comment below. */
! 5754: free_stack(common, 2);
! 5755: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0);
! 5756: }
! 5757: }
! 5758:
! 5759: if (ket == OP_KETRMAX)
! 5760: {
! 5761: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5762: CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_fallback)->recursivehotpath);
! 5763: if (bra == OP_BRAZERO)
! 5764: {
! 5765: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 5766: JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_fallback)->zerohotpath);
! 5767: JUMPHERE(brazero);
! 5768: }
! 5769: free_stack(common, 1);
! 5770: }
! 5771: else if (ket == OP_KETRMIN)
! 5772: {
! 5773: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5774:
! 5775: /* OP_ONCE removes everything in case of a fallback, so we don't
! 5776: need to explicitly release the STR_PTR. The extra release would
! 5777: affect badly the free_stack(2) above. */
! 5778: if (opcode != OP_ONCE)
! 5779: free_stack(common, 1);
! 5780: CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, rminlabel);
! 5781: if (opcode == OP_ONCE)
! 5782: free_stack(common, bra == OP_BRAMINZERO ? 2 : 1);
! 5783: else if (bra == OP_BRAMINZERO)
! 5784: free_stack(common, 1);
! 5785: }
! 5786: else if (bra == OP_BRAZERO)
! 5787: {
! 5788: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5789: JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_fallback)->zerohotpath);
! 5790: JUMPHERE(brazero);
! 5791: }
! 5792: }
! 5793:
! 5794: static void compile_bracketpos_fallbackpath(compiler_common *common, struct fallback_common *current)
! 5795: {
! 5796: DEFINE_COMPILER;
! 5797: int offset;
! 5798: struct sljit_jump *jump;
! 5799:
! 5800: if (CURRENT_AS(bracketpos_fallback)->framesize < 0)
! 5801: {
! 5802: if (*current->cc == OP_CBRAPOS || *current->cc == OP_SCBRAPOS)
! 5803: {
! 5804: offset = (GET2(current->cc, 1 + LINK_SIZE)) << 1;
! 5805: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5806: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
! 5807: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
! 5808: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP2, 0);
! 5809: }
! 5810: set_jumps(current->topfallbacks, LABEL());
! 5811: free_stack(common, CURRENT_AS(bracketpos_fallback)->stacksize);
! 5812: return;
! 5813: }
! 5814:
! 5815: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(bracketpos_fallback)->localptr);
! 5816: add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
! 5817:
! 5818: if (current->topfallbacks)
! 5819: {
! 5820: jump = JUMP(SLJIT_JUMP);
! 5821: set_jumps(current->topfallbacks, LABEL());
! 5822: /* Drop the stack frame. */
! 5823: free_stack(common, CURRENT_AS(bracketpos_fallback)->stacksize);
! 5824: JUMPHERE(jump);
! 5825: }
! 5826: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(bracketpos_fallback)->localptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracketpos_fallback)->framesize * sizeof(sljit_w));
! 5827: }
! 5828:
! 5829: static void compile_braminzero_fallbackpath(compiler_common *common, struct fallback_common *current)
! 5830: {
! 5831: assert_fallback fallback;
! 5832:
! 5833: current->top = NULL;
! 5834: current->topfallbacks = NULL;
! 5835: current->nextfallbacks = NULL;
! 5836: if (current->cc[1] > OP_ASSERTBACK_NOT)
! 5837: {
! 5838: /* Manual call of compile_bracket_hotpath and compile_bracket_fallbackpath. */
! 5839: compile_bracket_hotpath(common, current->cc, current);
! 5840: compile_bracket_fallbackpath(common, current->top);
! 5841: }
! 5842: else
! 5843: {
! 5844: memset(&fallback, 0, sizeof(fallback));
! 5845: fallback.common.cc = current->cc;
! 5846: fallback.hotpath = CURRENT_AS(braminzero_fallback)->hotpath;
! 5847: /* Manual call of compile_assert_hotpath. */
! 5848: compile_assert_hotpath(common, current->cc, &fallback, FALSE);
! 5849: }
! 5850: SLJIT_ASSERT(!current->nextfallbacks && !current->topfallbacks);
! 5851: }
! 5852:
! 5853: static void compile_fallbackpath(compiler_common *common, struct fallback_common *current)
! 5854: {
! 5855: DEFINE_COMPILER;
! 5856:
! 5857: while (current)
! 5858: {
! 5859: if (current->nextfallbacks != NULL)
! 5860: set_jumps(current->nextfallbacks, LABEL());
! 5861: switch(*current->cc)
! 5862: {
! 5863: case OP_SET_SOM:
! 5864: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 5865: free_stack(common, 1);
! 5866: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), TMP1, 0);
! 5867: break;
! 5868:
! 5869: case OP_STAR:
! 5870: case OP_MINSTAR:
! 5871: case OP_PLUS:
! 5872: case OP_MINPLUS:
! 5873: case OP_QUERY:
! 5874: case OP_MINQUERY:
! 5875: case OP_UPTO:
! 5876: case OP_MINUPTO:
! 5877: case OP_EXACT:
! 5878: case OP_POSSTAR:
! 5879: case OP_POSPLUS:
! 5880: case OP_POSQUERY:
! 5881: case OP_POSUPTO:
! 5882: case OP_STARI:
! 5883: case OP_MINSTARI:
! 5884: case OP_PLUSI:
! 5885: case OP_MINPLUSI:
! 5886: case OP_QUERYI:
! 5887: case OP_MINQUERYI:
! 5888: case OP_UPTOI:
! 5889: case OP_MINUPTOI:
! 5890: case OP_EXACTI:
! 5891: case OP_POSSTARI:
! 5892: case OP_POSPLUSI:
! 5893: case OP_POSQUERYI:
! 5894: case OP_POSUPTOI:
! 5895: case OP_NOTSTAR:
! 5896: case OP_NOTMINSTAR:
! 5897: case OP_NOTPLUS:
! 5898: case OP_NOTMINPLUS:
! 5899: case OP_NOTQUERY:
! 5900: case OP_NOTMINQUERY:
! 5901: case OP_NOTUPTO:
! 5902: case OP_NOTMINUPTO:
! 5903: case OP_NOTEXACT:
! 5904: case OP_NOTPOSSTAR:
! 5905: case OP_NOTPOSPLUS:
! 5906: case OP_NOTPOSQUERY:
! 5907: case OP_NOTPOSUPTO:
! 5908: case OP_NOTSTARI:
! 5909: case OP_NOTMINSTARI:
! 5910: case OP_NOTPLUSI:
! 5911: case OP_NOTMINPLUSI:
! 5912: case OP_NOTQUERYI:
! 5913: case OP_NOTMINQUERYI:
! 5914: case OP_NOTUPTOI:
! 5915: case OP_NOTMINUPTOI:
! 5916: case OP_NOTEXACTI:
! 5917: case OP_NOTPOSSTARI:
! 5918: case OP_NOTPOSPLUSI:
! 5919: case OP_NOTPOSQUERYI:
! 5920: case OP_NOTPOSUPTOI:
! 5921: case OP_TYPESTAR:
! 5922: case OP_TYPEMINSTAR:
! 5923: case OP_TYPEPLUS:
! 5924: case OP_TYPEMINPLUS:
! 5925: case OP_TYPEQUERY:
! 5926: case OP_TYPEMINQUERY:
! 5927: case OP_TYPEUPTO:
! 5928: case OP_TYPEMINUPTO:
! 5929: case OP_TYPEEXACT:
! 5930: case OP_TYPEPOSSTAR:
! 5931: case OP_TYPEPOSPLUS:
! 5932: case OP_TYPEPOSQUERY:
! 5933: case OP_TYPEPOSUPTO:
! 5934: case OP_CLASS:
! 5935: case OP_NCLASS:
! 5936: case OP_XCLASS:
! 5937: compile_iterator_fallbackpath(common, current);
! 5938: break;
! 5939:
! 5940: case OP_REF:
! 5941: case OP_REFI:
! 5942: compile_ref_iterator_fallbackpath(common, current);
! 5943: break;
! 5944:
! 5945: case OP_RECURSE:
! 5946: compile_recurse_fallbackpath(common, current);
! 5947: break;
! 5948:
! 5949: case OP_ASSERT:
! 5950: case OP_ASSERT_NOT:
! 5951: case OP_ASSERTBACK:
! 5952: case OP_ASSERTBACK_NOT:
! 5953: compile_assert_fallbackpath(common, current);
! 5954: break;
! 5955:
! 5956: case OP_ONCE:
! 5957: case OP_ONCE_NC:
! 5958: case OP_BRA:
! 5959: case OP_CBRA:
! 5960: case OP_COND:
! 5961: case OP_SBRA:
! 5962: case OP_SCBRA:
! 5963: case OP_SCOND:
! 5964: compile_bracket_fallbackpath(common, current);
! 5965: break;
! 5966:
! 5967: case OP_BRAZERO:
! 5968: if (current->cc[1] > OP_ASSERTBACK_NOT)
! 5969: compile_bracket_fallbackpath(common, current);
! 5970: else
! 5971: compile_assert_fallbackpath(common, current);
! 5972: break;
! 5973:
! 5974: case OP_BRAPOS:
! 5975: case OP_CBRAPOS:
! 5976: case OP_SBRAPOS:
! 5977: case OP_SCBRAPOS:
! 5978: case OP_BRAPOSZERO:
! 5979: compile_bracketpos_fallbackpath(common, current);
! 5980: break;
! 5981:
! 5982: case OP_BRAMINZERO:
! 5983: compile_braminzero_fallbackpath(common, current);
! 5984: break;
! 5985:
! 5986: case OP_FAIL:
! 5987: case OP_ACCEPT:
! 5988: case OP_ASSERT_ACCEPT:
! 5989: set_jumps(current->topfallbacks, LABEL());
! 5990: break;
! 5991:
! 5992: default:
! 5993: SLJIT_ASSERT_STOP();
! 5994: break;
! 5995: }
! 5996: current = current->prev;
! 5997: }
! 5998: }
! 5999:
! 6000: static SLJIT_INLINE void compile_recurse(compiler_common *common)
! 6001: {
! 6002: DEFINE_COMPILER;
! 6003: uschar *cc = common->start + common->currententry->start;
! 6004: uschar *ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : 2);
! 6005: uschar *ccend = bracketend(cc);
! 6006: int localsize = get_localsize(common, ccbegin, ccend);
! 6007: int framesize = get_framesize(common, cc, TRUE);
! 6008: int alternativesize;
! 6009: BOOL needsframe;
! 6010: fallback_common altfallback;
! 6011: struct sljit_jump *jump;
! 6012:
! 6013: SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA || *cc == OP_CBRAPOS || *cc == OP_SCBRA || *cc == OP_SCBRAPOS);
! 6014: needsframe = framesize >= 0;
! 6015: if (!needsframe)
! 6016: framesize = 0;
! 6017: alternativesize = *(cc + GET(cc, 1)) == OP_ALT ? 1 : 0;
! 6018:
! 6019: SLJIT_ASSERT(common->currententry->entry == NULL);
! 6020: common->currententry->entry = LABEL();
! 6021: set_jumps(common->currententry->calls, common->currententry->entry);
! 6022:
! 6023: sljit_emit_fast_enter(compiler, TMP2, 0, 1, 5, 5, common->localsize);
! 6024: allocate_stack(common, localsize + framesize + alternativesize);
! 6025: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(localsize + framesize + alternativesize - 1), TMP2, 0);
! 6026: copy_locals(common, ccbegin, ccend, TRUE, localsize + framesize + alternativesize, framesize + alternativesize);
! 6027: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), RECURSIVE_HEAD, STACK_TOP, 0);
! 6028: if (needsframe)
! 6029: init_frame(common, cc, framesize + alternativesize - 1, alternativesize, FALSE);
! 6030:
! 6031: if (alternativesize > 0)
! 6032: OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
! 6033:
! 6034: memset(&altfallback, 0, sizeof(fallback_common));
! 6035: common->acceptlabel = NULL;
! 6036: common->accept = NULL;
! 6037: altfallback.cc = ccbegin;
! 6038: cc += GET(cc, 1);
! 6039: while (1)
! 6040: {
! 6041: altfallback.top = NULL;
! 6042: altfallback.topfallbacks = NULL;
! 6043:
! 6044: if (altfallback.cc != ccbegin)
! 6045: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
! 6046:
! 6047: compile_hotpath(common, altfallback.cc, cc, &altfallback);
! 6048: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 6049: return;
! 6050:
! 6051: add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP));
! 6052:
! 6053: compile_fallbackpath(common, altfallback.top);
! 6054: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 6055: return;
! 6056: set_jumps(altfallback.topfallbacks, LABEL());
! 6057:
! 6058: if (*cc != OP_ALT)
! 6059: break;
! 6060:
! 6061: altfallback.cc = cc + 1 + LINK_SIZE;
! 6062: cc += GET(cc, 1);
! 6063: }
! 6064: /* None of them matched. */
! 6065: OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0);
! 6066: jump = JUMP(SLJIT_JUMP);
! 6067:
! 6068: set_jumps(common->accept, LABEL());
! 6069: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), RECURSIVE_HEAD);
! 6070: if (needsframe)
! 6071: {
! 6072: OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0));
! 6073: OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_w));
! 6074: add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
! 6075: OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_w));
! 6076: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), TMP3, 0);
! 6077: }
! 6078: OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 1);
! 6079:
! 6080: JUMPHERE(jump);
! 6081: copy_locals(common, ccbegin, ccend, FALSE, localsize + framesize + alternativesize, framesize + alternativesize);
! 6082: free_stack(common, localsize + framesize + alternativesize);
! 6083: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), sizeof(sljit_w));
! 6084: OP1(SLJIT_MOV, TMP1, 0, TMP3, 0);
! 6085: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), RECURSIVE_HEAD, TMP2, 0);
! 6086: sljit_emit_fast_return(compiler, SLJIT_MEM1(STACK_TOP), 0);
! 6087: }
! 6088:
! 6089: #undef COMPILE_FALLBACKPATH
! 6090: #undef CURRENT_AS
! 6091:
! 6092: void
! 6093: _pcre_jit_compile(const real_pcre *re, pcre_extra *extra)
! 6094: {
! 6095: struct sljit_compiler *compiler;
! 6096: fallback_common rootfallback;
! 6097: compiler_common common_data;
! 6098: compiler_common *common = &common_data;
! 6099: const uschar *tables = re->tables;
! 6100: pcre_study_data *study;
! 6101: uschar *ccend;
! 6102: executable_function *function;
! 6103: void *executable_func;
! 6104: sljit_uw executable_size;
! 6105: struct sljit_label *leave;
! 6106: struct sljit_label *mainloop = NULL;
! 6107: struct sljit_label *empty_match_found;
! 6108: struct sljit_label *empty_match_fallback;
! 6109: struct sljit_jump *alloc_error;
! 6110: struct sljit_jump *reqbyte_notfound = NULL;
! 6111: struct sljit_jump *empty_match;
! 6112:
! 6113: SLJIT_ASSERT((extra->flags & PCRE_EXTRA_STUDY_DATA) != 0);
! 6114: study = extra->study_data;
! 6115:
! 6116: if (!tables)
! 6117: tables = _pcre_default_tables;
! 6118:
! 6119: memset(&rootfallback, 0, sizeof(fallback_common));
! 6120: rootfallback.cc = (uschar *)re + re->name_table_offset + re->name_count * re->name_entry_size;
! 6121:
! 6122: common->compiler = NULL;
! 6123: common->start = rootfallback.cc;
! 6124: common->cbraptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_w);
! 6125: common->fcc = tables + fcc_offset;
! 6126: common->lcc = (sljit_w)(tables + lcc_offset);
! 6127: common->nltype = NLTYPE_FIXED;
! 6128: switch(re->options & PCRE_NEWLINE_BITS)
! 6129: {
! 6130: case 0:
! 6131: /* Compile-time default */
! 6132: switch (NEWLINE)
! 6133: {
! 6134: case -1: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break;
! 6135: case -2: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break;
! 6136: default: common->newline = NEWLINE; break;
! 6137: }
! 6138: break;
! 6139: case PCRE_NEWLINE_CR: common->newline = CHAR_CR; break;
! 6140: case PCRE_NEWLINE_LF: common->newline = CHAR_NL; break;
! 6141: case PCRE_NEWLINE_CR+
! 6142: PCRE_NEWLINE_LF: common->newline = (CHAR_CR << 8) | CHAR_NL; break;
! 6143: case PCRE_NEWLINE_ANY: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break;
! 6144: case PCRE_NEWLINE_ANYCRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break;
! 6145: default: return;
! 6146: }
! 6147: if ((re->options & PCRE_BSR_ANYCRLF) != 0)
! 6148: common->bsr_nltype = NLTYPE_ANYCRLF;
! 6149: else if ((re->options & PCRE_BSR_UNICODE) != 0)
! 6150: common->bsr_nltype = NLTYPE_ANY;
! 6151: else
! 6152: {
! 6153: #ifdef BSR_ANYCRLF
! 6154: common->bsr_nltype = NLTYPE_ANYCRLF;
! 6155: #else
! 6156: common->bsr_nltype = NLTYPE_ANY;
! 6157: #endif
! 6158: }
! 6159: common->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
! 6160: common->ctypes = (sljit_w)(tables + ctypes_offset);
! 6161: common->name_table = (sljit_w)re + re->name_table_offset;
! 6162: common->name_count = re->name_count;
! 6163: common->name_entry_size = re->name_entry_size;
! 6164: common->acceptlabel = NULL;
! 6165: common->stubs = NULL;
! 6166: common->entries = NULL;
! 6167: common->currententry = NULL;
! 6168: common->accept = NULL;
! 6169: common->calllimit = NULL;
! 6170: common->stackalloc = NULL;
! 6171: common->revertframes = NULL;
! 6172: common->wordboundary = NULL;
! 6173: common->anynewline = NULL;
! 6174: common->hspace = NULL;
! 6175: common->vspace = NULL;
! 6176: common->casefulcmp = NULL;
! 6177: common->caselesscmp = NULL;
! 6178: common->jscript_compat = (re->options & PCRE_JAVASCRIPT_COMPAT) != 0;
! 6179: #ifdef SUPPORT_UTF8
! 6180: common->utf8 = (re->options & PCRE_UTF8) != 0;
! 6181: #ifdef SUPPORT_UCP
! 6182: common->useucp = (re->options & PCRE_UCP) != 0;
! 6183: #endif
! 6184: common->utf8readchar = NULL;
! 6185: common->utf8readtype8 = NULL;
! 6186: #endif
! 6187: #ifdef SUPPORT_UCP
! 6188: common->getucd = NULL;
! 6189: #endif
! 6190: ccend = bracketend(rootfallback.cc);
! 6191: SLJIT_ASSERT(*rootfallback.cc == OP_BRA && ccend[-(1 + LINK_SIZE)] == OP_KET);
! 6192: common->localsize = get_localspace(common, rootfallback.cc, ccend);
! 6193: if (common->localsize < 0)
! 6194: return;
! 6195: common->localsize += common->cbraptr + (re->top_bracket + 1) * sizeof(sljit_w);
! 6196: if (common->localsize > SLJIT_MAX_LOCAL_SIZE)
! 6197: return;
! 6198: common->localptrs = (int*)SLJIT_MALLOC((ccend - rootfallback.cc) * sizeof(int));
! 6199: if (!common->localptrs)
! 6200: return;
! 6201: memset(common->localptrs, 0, (ccend - rootfallback.cc) * sizeof(int));
! 6202: set_localptrs(common, common->cbraptr + (re->top_bracket + 1) * sizeof(sljit_w), ccend);
! 6203:
! 6204: compiler = sljit_create_compiler();
! 6205: if (!compiler)
! 6206: {
! 6207: SLJIT_FREE(common->localptrs);
! 6208: return;
! 6209: }
! 6210: common->compiler = compiler;
! 6211:
! 6212: /* Main pcre_jit_exec entry. */
! 6213: sljit_emit_enter(compiler, 1, 5, 5, common->localsize);
! 6214:
! 6215: /* Register init. */
! 6216: reset_ovector(common, (re->top_bracket + 1) * 2);
! 6217: if ((re->flags & PCRE_REQCHSET) != 0)
! 6218: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), REQ_BYTE_PTR, SLJIT_TEMPORARY_REG1, 0);
! 6219:
! 6220: OP1(SLJIT_MOV, ARGUMENTS, 0, SLJIT_GENERAL_REG1, 0);
! 6221: OP1(SLJIT_MOV, TMP1, 0, SLJIT_GENERAL_REG1, 0);
! 6222: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
! 6223: OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, end));
! 6224: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
! 6225: OP1(SLJIT_MOV_SI, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, calllimit));
! 6226: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, base));
! 6227: OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, limit));
! 6228: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CALL_LIMIT, TMP1, 0);
! 6229:
! 6230: /* Main part of the matching */
! 6231: if ((re->options & PCRE_ANCHORED) == 0)
! 6232: {
! 6233: mainloop = mainloop_entry(common, (re->flags & PCRE_HASCRORLF) != 0, (re->options & PCRE_FIRSTLINE) != 0);
! 6234: /* Forward search if possible. */
! 6235: if ((re->flags & PCRE_FIRSTSET) != 0)
! 6236: fast_forward_first_byte(common, re->first_byte, (re->options & PCRE_FIRSTLINE) != 0);
! 6237: else if ((re->flags & PCRE_STARTLINE) != 0)
! 6238: fast_forward_newline(common, (re->options & PCRE_FIRSTLINE) != 0);
! 6239: else if ((re->flags & PCRE_STARTLINE) == 0 && study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0)
! 6240: fast_forward_start_bits(common, (sljit_uw)study->start_bits, (re->options & PCRE_FIRSTLINE) != 0);
! 6241: }
! 6242: if ((re->flags & PCRE_REQCHSET) != 0)
! 6243: reqbyte_notfound = search_requested_char(common, re->req_byte, (re->flags & PCRE_FIRSTSET) != 0);
! 6244:
! 6245: /* Store the current STR_PTR in OVECTOR(0). */
! 6246: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), STR_PTR, 0);
! 6247: /* Copy the limit of allowed recursions. */
! 6248: OP1(SLJIT_MOV, CALL_COUNT, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CALL_LIMIT);
! 6249:
! 6250: compile_hotpath(common, rootfallback.cc, ccend, &rootfallback);
! 6251: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 6252: {
! 6253: sljit_free_compiler(compiler);
! 6254: SLJIT_FREE(common->localptrs);
! 6255: return;
! 6256: }
! 6257:
! 6258: empty_match = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0));
! 6259: empty_match_found = LABEL();
! 6260:
! 6261: common->acceptlabel = LABEL();
! 6262: if (common->accept != NULL)
! 6263: set_jumps(common->accept, common->acceptlabel);
! 6264:
! 6265: /* This means we have a match. Update the ovector. */
! 6266: copy_ovector(common, re->top_bracket + 1);
! 6267: leave = LABEL();
! 6268: sljit_emit_return(compiler, SLJIT_UNUSED, 0);
! 6269:
! 6270: empty_match_fallback = LABEL();
! 6271: compile_fallbackpath(common, rootfallback.top);
! 6272: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 6273: {
! 6274: sljit_free_compiler(compiler);
! 6275: SLJIT_FREE(common->localptrs);
! 6276: return;
! 6277: }
! 6278:
! 6279: SLJIT_ASSERT(rootfallback.prev == NULL);
! 6280:
! 6281: /* Check we have remaining characters. */
! 6282: OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0));
! 6283:
! 6284: if ((re->options & PCRE_ANCHORED) == 0)
! 6285: {
! 6286: if ((re->options & PCRE_FIRSTLINE) == 0)
! 6287: {
! 6288: if (study != NULL && study->minlength > 1)
! 6289: {
! 6290: OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, study->minlength);
! 6291: CMPTO(SLJIT_C_LESS_EQUAL, TMP1, 0, STR_END, 0, mainloop);
! 6292: }
! 6293: else
! 6294: CMPTO(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0, mainloop);
! 6295: }
! 6296: else
! 6297: {
! 6298: if (study != NULL && study->minlength > 1)
! 6299: {
! 6300: OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, study->minlength);
! 6301: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, STR_END, 0);
! 6302: COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_GREATER);
! 6303: OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), FIRSTLINE_END);
! 6304: COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_GREATER_EQUAL);
! 6305: JUMPTO(SLJIT_C_ZERO, mainloop);
! 6306: }
! 6307: else
! 6308: CMPTO(SLJIT_C_LESS, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), FIRSTLINE_END, mainloop);
! 6309: }
! 6310: }
! 6311:
! 6312: if (reqbyte_notfound != NULL)
! 6313: JUMPHERE(reqbyte_notfound);
! 6314: /* Copy OVECTOR(1) to OVECTOR(0) */
! 6315: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1));
! 6316: OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH);
! 6317: JUMPTO(SLJIT_JUMP, leave);
! 6318:
! 6319: flush_stubs(common);
! 6320:
! 6321: JUMPHERE(empty_match);
! 6322: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 6323: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty));
! 6324: CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_fallback);
! 6325: OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart));
! 6326: CMPTO(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_found);
! 6327: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
! 6328: CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found);
! 6329: JUMPTO(SLJIT_JUMP, empty_match_fallback);
! 6330:
! 6331: common->currententry = common->entries;
! 6332: while (common->currententry != NULL)
! 6333: {
! 6334: /* Might add new entries. */
! 6335: compile_recurse(common);
! 6336: if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
! 6337: {
! 6338: sljit_free_compiler(compiler);
! 6339: SLJIT_FREE(common->localptrs);
! 6340: return;
! 6341: }
! 6342: flush_stubs(common);
! 6343: common->currententry = common->currententry->next;
! 6344: }
! 6345:
! 6346: /* Allocating stack, returns with PCRE_ERROR_JIT_STACKLIMIT if fails. */
! 6347: /* This is a (really) rare case. */
! 6348: set_jumps(common->stackalloc, LABEL());
! 6349: /* RETURN_ADDR is not a saved register. */
! 6350: sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, 1, 5, 5, common->localsize);
! 6351: OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, TMP2, 0);
! 6352: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 6353: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
! 6354: OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, top), STACK_TOP, 0);
! 6355: OP2(SLJIT_ADD, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit), SLJIT_IMM, STACK_GROWTH_RATE);
! 6356:
! 6357: sljit_emit_ijump(compiler, SLJIT_CALL2, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize));
! 6358: alloc_error = CMP(SLJIT_C_NOT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
! 6359: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
! 6360: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
! 6361: OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, top));
! 6362: OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit));
! 6363: OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1);
! 6364: sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0);
! 6365:
! 6366: /* Allocation failed. */
! 6367: JUMPHERE(alloc_error);
! 6368: /* We break the return address cache here, but this is a really rare case. */
! 6369: OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_JIT_STACKLIMIT);
! 6370: JUMPTO(SLJIT_JUMP, leave);
! 6371:
! 6372: /* Call limit reached. */
! 6373: set_jumps(common->calllimit, LABEL());
! 6374: OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_MATCHLIMIT);
! 6375: JUMPTO(SLJIT_JUMP, leave);
! 6376:
! 6377: if (common->revertframes != NULL)
! 6378: {
! 6379: set_jumps(common->revertframes, LABEL());
! 6380: do_revertframes(common);
! 6381: }
! 6382: if (common->wordboundary != NULL)
! 6383: {
! 6384: set_jumps(common->wordboundary, LABEL());
! 6385: check_wordboundary(common);
! 6386: }
! 6387: if (common->anynewline != NULL)
! 6388: {
! 6389: set_jumps(common->anynewline, LABEL());
! 6390: check_anynewline(common);
! 6391: }
! 6392: if (common->hspace != NULL)
! 6393: {
! 6394: set_jumps(common->hspace, LABEL());
! 6395: check_hspace(common);
! 6396: }
! 6397: if (common->vspace != NULL)
! 6398: {
! 6399: set_jumps(common->vspace, LABEL());
! 6400: check_vspace(common);
! 6401: }
! 6402: if (common->casefulcmp != NULL)
! 6403: {
! 6404: set_jumps(common->casefulcmp, LABEL());
! 6405: do_casefulcmp(common);
! 6406: }
! 6407: if (common->caselesscmp != NULL)
! 6408: {
! 6409: set_jumps(common->caselesscmp, LABEL());
! 6410: do_caselesscmp(common);
! 6411: }
! 6412: #ifdef SUPPORT_UTF8
! 6413: if (common->utf8readchar != NULL)
! 6414: {
! 6415: set_jumps(common->utf8readchar, LABEL());
! 6416: do_utf8readchar(common);
! 6417: }
! 6418: if (common->utf8readtype8 != NULL)
! 6419: {
! 6420: set_jumps(common->utf8readtype8, LABEL());
! 6421: do_utf8readtype8(common);
! 6422: }
! 6423: #endif
! 6424: #ifdef SUPPORT_UCP
! 6425: if (common->getucd != NULL)
! 6426: {
! 6427: set_jumps(common->getucd, LABEL());
! 6428: do_getucd(common);
! 6429: }
! 6430: #endif
! 6431:
! 6432: SLJIT_FREE(common->localptrs);
! 6433: executable_func = sljit_generate_code(compiler);
! 6434: executable_size = sljit_get_generated_code_size(compiler);
! 6435: sljit_free_compiler(compiler);
! 6436: if (executable_func == NULL)
! 6437: return;
! 6438:
! 6439: function = SLJIT_MALLOC(sizeof(executable_function));
! 6440: if (function == NULL)
! 6441: {
! 6442: /* This case is highly unlikely since we just recently
! 6443: freed a lot of memory. Although not impossible. */
! 6444: sljit_free_code(executable_func);
! 6445: return;
! 6446: }
! 6447:
! 6448: function->executable_func = executable_func;
! 6449: function->executable_size = executable_size;
! 6450: function->callback = NULL;
! 6451: function->userdata = NULL;
! 6452: extra->executable_jit = function;
! 6453: extra->flags |= PCRE_EXTRA_EXECUTABLE_JIT;
! 6454: }
! 6455:
! 6456: static int jit_machine_stack_exec(jit_arguments *arguments, executable_function *function)
! 6457: {
! 6458: union {
! 6459: void* executable_func;
! 6460: jit_function call_executable_func;
! 6461: } convert_executable_func;
! 6462: uschar local_area[LOCAL_SPACE_SIZE];
! 6463: struct sljit_stack local_stack;
! 6464:
! 6465: local_stack.top = (sljit_w)&local_area;
! 6466: local_stack.base = local_stack.top;
! 6467: local_stack.limit = local_stack.base + LOCAL_SPACE_SIZE;
! 6468: local_stack.max_limit = local_stack.limit;
! 6469: arguments->stack = &local_stack;
! 6470: convert_executable_func.executable_func = function->executable_func;
! 6471: return convert_executable_func.call_executable_func(arguments);
! 6472: }
! 6473:
! 6474: int
! 6475: _pcre_jit_exec(const real_pcre *re, void *executable_func,
! 6476: PCRE_SPTR subject, int length, int start_offset, int options,
! 6477: int match_limit, int *offsets, int offsetcount)
! 6478: {
! 6479: executable_function *function = (executable_function*)executable_func;
! 6480: union {
! 6481: void* executable_func;
! 6482: jit_function call_executable_func;
! 6483: } convert_executable_func;
! 6484: jit_arguments arguments;
! 6485: int maxoffsetcount;
! 6486: int retval;
! 6487:
! 6488: /* Sanity checks should be handled by pcre_exec. */
! 6489: arguments.stack = NULL;
! 6490: arguments.str = subject + start_offset;
! 6491: arguments.begin = subject;
! 6492: arguments.end = subject + length;
! 6493: arguments.calllimit = match_limit; /* JIT decreases this value less times. */
! 6494: arguments.notbol = (options & PCRE_NOTBOL) != 0;
! 6495: arguments.noteol = (options & PCRE_NOTEOL) != 0;
! 6496: arguments.notempty = (options & PCRE_NOTEMPTY) != 0;
! 6497: arguments.notempty_atstart = (options & PCRE_NOTEMPTY_ATSTART) != 0;
! 6498: arguments.offsets = offsets;
! 6499:
! 6500: /* pcre_exec() rounds offsetcount to a multiple of 3, and then uses only 2/3 of
! 6501: the output vector for storing captured strings, with the remainder used as
! 6502: workspace. We don't need the workspace here. For compatibility, we limit the
! 6503: number of captured strings in the same way as pcre_exec(), so that the user
! 6504: gets the same result with and without JIT. */
! 6505:
! 6506: offsetcount = ((offsetcount - (offsetcount % 3)) * 2)/3;
! 6507: maxoffsetcount = (re->top_bracket + 1) * 2;
! 6508: if (offsetcount > maxoffsetcount)
! 6509: offsetcount = maxoffsetcount;
! 6510: arguments.offsetcount = offsetcount;
! 6511:
! 6512: if (function->callback)
! 6513: arguments.stack = (struct sljit_stack*)function->callback(function->userdata);
! 6514: else
! 6515: arguments.stack = (struct sljit_stack*)function->userdata;
! 6516:
! 6517: if (arguments.stack == NULL)
! 6518: retval = jit_machine_stack_exec(&arguments, function);
! 6519: else
! 6520: {
! 6521: convert_executable_func.executable_func = function->executable_func;
! 6522: retval = convert_executable_func.call_executable_func(&arguments);
! 6523: }
! 6524:
! 6525: if (retval * 2 > offsetcount)
! 6526: retval = 0;
! 6527: return retval;
! 6528: }
! 6529:
! 6530: void
! 6531: _pcre_jit_free(void *executable_func)
! 6532: {
! 6533: executable_function *function = (executable_function*)executable_func;
! 6534: sljit_free_code(function->executable_func);
! 6535: SLJIT_FREE(function);
! 6536: }
! 6537:
! 6538: int
! 6539: _pcre_jit_get_size(void *executable_func)
! 6540: {
! 6541: return ((executable_function*)executable_func)->executable_size;
! 6542: }
! 6543:
! 6544: PCRE_EXP_DECL pcre_jit_stack *
! 6545: pcre_jit_stack_alloc(int startsize, int maxsize)
! 6546: {
! 6547: if (startsize < 1 || maxsize < 1)
! 6548: return NULL;
! 6549: if (startsize > maxsize)
! 6550: startsize = maxsize;
! 6551: startsize = (startsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
! 6552: maxsize = (maxsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
! 6553: return (pcre_jit_stack*)sljit_allocate_stack(startsize, maxsize);
! 6554: }
! 6555:
! 6556: PCRE_EXP_DECL void
! 6557: pcre_jit_stack_free(pcre_jit_stack *stack)
! 6558: {
! 6559: sljit_free_stack((struct sljit_stack*)stack);
! 6560: }
! 6561:
! 6562: PCRE_EXP_DECL void
! 6563: pcre_assign_jit_stack(pcre_extra *extra, pcre_jit_callback callback, void *userdata)
! 6564: {
! 6565: executable_function *function;
! 6566: if (extra != NULL &&
! 6567: (extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 &&
! 6568: extra->executable_jit != NULL)
! 6569: {
! 6570: function = (executable_function*)extra->executable_jit;
! 6571: function->callback = callback;
! 6572: function->userdata = userdata;
! 6573: }
! 6574: }
! 6575:
! 6576: #else /* SUPPORT_JIT */
! 6577:
! 6578: /* These are dummy functions to avoid linking errors when JIT support is not
! 6579: being compiled. */
! 6580:
! 6581: PCRE_EXP_DECL pcre_jit_stack *
! 6582: pcre_jit_stack_alloc(int startsize, int maxsize)
! 6583: {
! 6584: (void)startsize;
! 6585: (void)maxsize;
! 6586: return NULL;
! 6587: }
! 6588:
! 6589: PCRE_EXP_DECL void
! 6590: pcre_jit_stack_free(pcre_jit_stack *stack)
! 6591: {
! 6592: (void)stack;
! 6593: }
! 6594:
! 6595: PCRE_EXP_DECL void
! 6596: pcre_assign_jit_stack(pcre_extra *extra, pcre_jit_callback callback, void *userdata)
! 6597: {
! 6598: (void)extra;
! 6599: (void)callback;
! 6600: (void)userdata;
! 6601: }
! 6602:
! 6603: #endif
! 6604:
! 6605: /* End of pcre_jit_compile.c */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>