diff --git a/pkgs/development/libraries/pcre/default.nix b/pkgs/development/libraries/pcre/default.nix index a34f3e5e132..5a55db53348 100644 --- a/pkgs/development/libraries/pcre/default.nix +++ b/pkgs/development/libraries/pcre/default.nix @@ -12,6 +12,9 @@ stdenv.mkDerivation rec { sha256 = "17bqykp604p7376wj3q2nmjdhrb6v1ny8q08zdwi7qvc02l9wrsi"; }; + # A bundle of fixes which should be removed for 8.38 + patches = [ ./fixes.patch ]; + outputs = [ "out" "doc" "man" ]; configureFlags = '' diff --git a/pkgs/development/libraries/pcre/fixes.patch b/pkgs/development/libraries/pcre/fixes.patch new file mode 100644 index 00000000000..3b39128d7e4 --- /dev/null +++ b/pkgs/development/libraries/pcre/fixes.patch @@ -0,0 +1,3538 @@ +Index: pcre_jit_compile.c +=================================================================== +--- pcre_jit_compile.c (revision 1554) ++++ pcre_jit_compile.c (working copy) +@@ -1064,6 +1064,7 @@ + pcre_uchar *end = NULL; + int private_data_ptr = *private_data_start; + int space, size, bracketlen; ++BOOL repeat_check = TRUE; + + while (cc < ccend) + { +@@ -1071,9 +1072,10 @@ + size = 0; + bracketlen = 0; + if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE) +- return; ++ break; + +- if (*cc == OP_ONCE || *cc == OP_ONCE_NC || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND) ++ if (repeat_check && (*cc == OP_ONCE || *cc == OP_ONCE_NC || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND)) ++ { + if (detect_repeat(common, cc)) + { + /* These brackets are converted to repeats, so no global +@@ -1081,6 +1083,8 @@ + if (cc >= end) + end = bracketend(cc); + } ++ } ++ repeat_check = TRUE; + + switch(*cc) + { +@@ -1136,6 +1140,13 @@ + bracketlen = 1 + LINK_SIZE + IMM2_SIZE; + break; + ++ case OP_BRAZERO: ++ case OP_BRAMINZERO: ++ case OP_BRAPOSZERO: ++ repeat_check = FALSE; ++ size = 1; ++ break; ++ + CASE_ITERATOR_PRIVATE_DATA_1 + space = 1; + size = -2; +@@ -1162,12 +1173,17 @@ + size = 1; + break; + +- CASE_ITERATOR_TYPE_PRIVATE_DATA_2B ++ case OP_TYPEUPTO: + if (cc[1 + IMM2_SIZE] != OP_ANYNL && cc[1 + IMM2_SIZE] != OP_EXTUNI) + space = 2; + size = 1 + IMM2_SIZE; + break; + ++ case OP_TYPEMINUPTO: ++ space = 2; ++ size = 1 + IMM2_SIZE; ++ break; ++ + case OP_CLASS: + case OP_NCLASS: + size += 1 + 32 / sizeof(pcre_uchar); +@@ -1316,6 +1332,13 @@ + cc += 1 + LINK_SIZE + IMM2_SIZE; + break; + ++ case OP_THEN: ++ stack_restore = TRUE; ++ if (common->control_head_ptr != 0) ++ *needs_control_head = TRUE; ++ cc ++; ++ break; ++ + default: + stack_restore = TRUE; + /* Fall through. */ +@@ -2220,6 +2243,7 @@ + SLJIT_ASSERT_STOP(); + break; + } ++ SLJIT_ASSERT(current > (sljit_sw*)current[-1]); + current = (sljit_sw*)current[-1]; + } + return -1; +@@ -3209,7 +3233,7 @@ + bytes[0] = len; + } + +-static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uint32 *chars, pcre_uint8 *bytes, int max_chars) ++static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uint32 *chars, pcre_uint8 *bytes, int max_chars, pcre_uint32 *rec_count) + { + /* Recursive function, which scans prefix literals. */ + BOOL last, any, caseless; +@@ -3227,9 +3251,14 @@ + repeat = 1; + while (TRUE) + { ++ if (*rec_count == 0) ++ return 0; ++ (*rec_count)--; ++ + last = TRUE; + any = FALSE; + caseless = FALSE; ++ + switch (*cc) + { + case OP_CHARI: +@@ -3291,7 +3320,7 @@ + #ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc); + #endif +- max_chars = scan_prefix(common, cc + len, chars, bytes, max_chars); ++ max_chars = scan_prefix(common, cc + len, chars, bytes, max_chars, rec_count); + if (max_chars == 0) + return consumed; + last = FALSE; +@@ -3314,7 +3343,7 @@ + alternative = cc + GET(cc, 1); + while (*alternative == OP_ALT) + { +- max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, bytes, max_chars); ++ max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, bytes, max_chars, rec_count); + if (max_chars == 0) + return consumed; + alternative += GET(alternative, 1); +@@ -3556,6 +3585,7 @@ + int range_right = -1, range_len = 3 - 1; + sljit_ub *update_table = NULL; + BOOL in_range; ++pcre_uint32 rec_count; + + for (i = 0; i < MAX_N_CHARS; i++) + { +@@ -3564,7 +3594,8 @@ + bytes[i * MAX_N_BYTES] = 0; + } + +-max = scan_prefix(common, common->start, chars, bytes, MAX_N_CHARS); ++rec_count = 10000; ++max = scan_prefix(common, common->start, chars, bytes, MAX_N_CHARS, &rec_count); + + if (max <= 1) + return FALSE; +@@ -4311,8 +4342,10 @@ + case 4: + if ((ranges[1] - ranges[0]) == (ranges[3] - ranges[2]) + && (ranges[0] | (ranges[2] - ranges[0])) == ranges[2] ++ && (ranges[1] & (ranges[2] - ranges[0])) == 0 + && is_powerof2(ranges[2] - ranges[0])) + { ++ SLJIT_ASSERT((ranges[0] & (ranges[2] - ranges[0])) == 0 && (ranges[2] & ranges[3] & (ranges[2] - ranges[0])) != 0); + OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[0]); + if (ranges[2] + 1 != ranges[3]) + { +@@ -4900,9 +4933,10 @@ + if (!check_class_ranges(common, (const pcre_uint8 *)cc, FALSE, TRUE, list)) + { + #ifdef COMPILE_PCRE8 +- SLJIT_ASSERT(common->utf); ++ jump = NULL; ++ if (common->utf) + #endif +- jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); ++ jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); + + OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); + OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); +@@ -4911,7 +4945,10 @@ + OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + add_jump(compiler, list, JUMP(SLJIT_NOT_ZERO)); + +- JUMPHERE(jump); ++#ifdef COMPILE_PCRE8 ++ if (common->utf) ++#endif ++ JUMPHERE(jump); + } + + OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); +@@ -7665,6 +7702,10 @@ + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); + } + ++ /* Even if the match is empty, we need to reset the control head. */ ++ if (needs_control_head) ++ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack)); ++ + if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS) + add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0)); + +@@ -7692,6 +7733,10 @@ + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw), STR_PTR, 0); + } + ++ /* Even if the match is empty, we need to reset the control head. */ ++ if (needs_control_head) ++ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack)); ++ + if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS) + add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0)); + +@@ -7704,9 +7749,6 @@ + } + } + +- if (needs_control_head) +- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack)); +- + JUMPTO(SLJIT_JUMP, loop); + flush_stubs(common); + +@@ -8441,8 +8483,7 @@ + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_PTR, 0); + } + BACKTRACK_AS(braminzero_backtrack)->matchingpath = LABEL(); +- if (cc[1] > OP_ASSERTBACK_NOT) +- count_match(common); ++ count_match(common); + break; + + case OP_ONCE: +@@ -9624,7 +9665,7 @@ + DEFINE_COMPILER; + pcre_uchar *cc = common->start + common->currententry->start; + pcre_uchar *ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : IMM2_SIZE); +-pcre_uchar *ccend = bracketend(cc); ++pcre_uchar *ccend = bracketend(cc) - (1 + LINK_SIZE); + BOOL needs_control_head; + int framesize = get_framesize(common, cc, NULL, TRUE, &needs_control_head); + int private_data_size = get_private_data_copy_length(common, ccbegin, ccend, needs_control_head); +@@ -9648,6 +9689,7 @@ + + sljit_emit_fast_enter(compiler, TMP2, 0); + allocate_stack(common, private_data_size + framesize + alternativesize); ++count_match(common); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(private_data_size + framesize + alternativesize - 1), TMP2, 0); + copy_private_data(common, ccbegin, ccend, TRUE, private_data_size + framesize + alternativesize, framesize + alternativesize, needs_control_head); + if (needs_control_head) +@@ -9992,6 +10034,7 @@ + OP1(SLJIT_MOV_UI, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match)); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, base)); + OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, limit)); ++OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0); + + if (mode == JIT_PARTIAL_SOFT_COMPILE) +Index: RunGrepTest +=================================================================== +--- RunGrepTest (revision 1554) ++++ RunGrepTest (working copy) +@@ -512,6 +512,14 @@ + (cd $srcdir; $valgrind $pcregrep --line-offsets '(?<=\Ka)' $builddir/testtemp1grep) >>testtrygrep 2>&1 + echo "RC=$?" >>testtrygrep + ++echo "---------------------------- Test 108 ------------------------------" >>testtrygrep ++(cd $srcdir; $valgrind $pcregrep -lq PATTERN ./testdata/grepinput ./testdata/grepinputx) >>testtrygrep ++echo "RC=$?" >>testtrygrep ++ ++echo "---------------------------- Test 109 -----------------------------" >>testtrygrep ++(cd $srcdir; $valgrind $pcregrep -cq lazy ./testdata/grepinput*) >>testtrygrep ++echo "RC=$?" >>testtrygrep ++ + # Now compare the results. + + $cf $srcdir/testdata/grepoutput testtrygrep +Index: pcre_compile.c +=================================================================== +--- pcre_compile.c (revision 1554) ++++ pcre_compile.c (working copy) +@@ -174,7 +174,7 @@ + -ESC_Z, CHAR_LEFT_SQUARE_BRACKET, + CHAR_BACKSLASH, CHAR_RIGHT_SQUARE_BRACKET, + CHAR_CIRCUMFLEX_ACCENT, CHAR_UNDERSCORE, +- CHAR_GRAVE_ACCENT, 7, ++ CHAR_GRAVE_ACCENT, ESC_a, + -ESC_b, 0, + -ESC_d, ESC_e, + ESC_f, 0, +@@ -202,9 +202,9 @@ + /* 68 */ 0, 0, '|', ',', '%', '_', '>', '?', + /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 78 */ 0, '`', ':', '#', '@', '\'', '=', '"', +-/* 80 */ 0, 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, ++/* 80 */ 0, ESC_a, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, + /* 88 */-ESC_h, 0, 0, '{', 0, 0, 0, 0, +-/* 90 */ 0, 0, -ESC_k, 'l', 0, ESC_n, 0, -ESC_p, ++/* 90 */ 0, 0, -ESC_k, 0, 0, ESC_n, 0, -ESC_p, + /* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0, + /* A0 */ 0, '~', -ESC_s, ESC_tee, 0,-ESC_v, -ESC_w, 0, + /* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0, +@@ -219,6 +219,12 @@ + /* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* F8 */ 0, 0, 0, 0, 0, 0, 0, 0 + }; ++ ++/* We also need a table of characters that may follow \c in an EBCDIC ++environment for characters 0-31. */ ++ ++static unsigned char ebcdic_escape_c[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; ++ + #endif + + +@@ -458,7 +464,7 @@ + "range out of order in character class\0" + "nothing to repeat\0" + /* 10 */ +- "operand of unlimited repeat could match the empty string\0" /** DEAD **/ ++ "internal error: invalid forward reference offset\0" + "internal error: unexpected repeat\0" + "unrecognized character after (? or (?-\0" + "POSIX named classes are supported only within a class\0" +@@ -527,7 +533,11 @@ + "different names for subpatterns of the same number are not allowed\0" + "(*MARK) must have an argument\0" + "this version of PCRE is not compiled with Unicode property support\0" ++#ifndef EBCDIC + "\\c must be followed by an ASCII character\0" ++#else ++ "\\c must be followed by a letter or one of [\\]^_?\0" ++#endif + "\\k is not followed by a braced, angle-bracketed, or quoted name\0" + /* 70 */ + "internal error: unknown opcode in find_fixedlength()\0" +@@ -1425,7 +1435,16 @@ + c ^= 0x40; + #else /* EBCDIC coding */ + if (c >= CHAR_a && c <= CHAR_z) c += 64; +- c ^= 0xC0; ++ if (c == CHAR_QUESTION_MARK) ++ c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff; ++ else ++ { ++ for (i = 0; i < 32; i++) ++ { ++ if (c == ebcdic_escape_c[i]) break; ++ } ++ if (i < 32) c = i; else *errorcodeptr = ERR68; ++ } + #endif + break; + +@@ -1799,7 +1818,7 @@ + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do cc += GET(cc, 1); while (*cc == OP_ALT); +- cc += PRIV(OP_lengths)[*cc]; ++ cc += 1 + LINK_SIZE; + break; + + /* Skip over things that don't match chars */ +@@ -2487,7 +2506,7 @@ + if (c == OP_BRA || c == OP_BRAPOS || + c == OP_CBRA || c == OP_CBRAPOS || + c == OP_ONCE || c == OP_ONCE_NC || +- c == OP_COND) ++ c == OP_COND || c == OP_SCOND) + { + BOOL empty_branch; + if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */ +@@ -3886,11 +3905,11 @@ + The problem in trying to be exactly like Perl is in the handling of escapes. We + have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX + class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code +-below handles the special case of \], but does not try to do any other escape +-processing. This makes it different from Perl for cases such as [:l\ower:] +-where Perl recognizes it as the POSIX class "lower" but PCRE does not recognize +-"l\ower". This is a lesser evil than not diagnosing bad classes when Perl does, +-I think. ++below handles the special cases \\ and \], but does not try to do any other ++escape processing. This makes it different from Perl for cases such as ++[:l\ower:] where Perl recognizes it as the POSIX class "lower" but PCRE does ++not recognize "l\ower". This is a lesser evil than not diagnosing bad classes ++when Perl does, I think. + + A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not. + It seems that the appearance of a nested POSIX class supersedes an apparent +@@ -3917,21 +3936,16 @@ + terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ + for (++ptr; *ptr != CHAR_NULL; ptr++) + { +- if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) ++ if (*ptr == CHAR_BACKSLASH && ++ (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ++ ptr[1] == CHAR_BACKSLASH)) + ptr++; +- else if (*ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE; +- else ++ else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) || ++ *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE; ++ else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) + { +- if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) +- { +- *endptr = ptr; +- return TRUE; +- } +- if (*ptr == CHAR_LEFT_SQUARE_BRACKET && +- (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || +- ptr[1] == CHAR_EQUALS_SIGN) && +- check_posix_syntax(ptr, endptr)) +- return FALSE; ++ *endptr = ptr; ++ return TRUE; + } + } + return FALSE; +@@ -3985,11 +3999,12 @@ + is called, the partially compiled regex must be temporarily terminated with + OP_END. + +-This function has been extended with the possibility of forward references for +-recursions and subroutine calls. It must also check the list of such references +-for the group we are dealing with. If it finds that one of the recursions in +-the current group is on this list, it adjusts the offset in the list, not the +-value in the reference (which is a group number). ++This function has been extended to cope with forward references for recursions ++and subroutine calls. It must check the list of such references for the ++group we are dealing with. If it finds that one of the recursions in the ++current group is on this list, it does not adjust the value in the reference ++(which is a group number). After the group has been scanned, all the offsets in ++the forward reference list for the group are adjusted. + + Arguments: + group points to the start of the group +@@ -4005,29 +4020,21 @@ + adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd, + size_t save_hwm_offset) + { ++int offset; ++pcre_uchar *hc; + pcre_uchar *ptr = group; + + while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL) + { +- int offset; +- pcre_uchar *hc; +- +- /* See if this recursion is on the forward reference list. If so, adjust the +- reference. */ +- + for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm; + hc += LINK_SIZE) + { + offset = (int)GET(hc, 0); +- if (cd->start_code + offset == ptr + 1) +- { +- PUT(hc, 0, offset + adjust); +- break; +- } ++ if (cd->start_code + offset == ptr + 1) break; + } + +- /* Otherwise, adjust the recursion offset if it's after the start of this +- group. */ ++ /* If we have not found this recursion on the forward reference list, adjust ++ the recursion's offset if it's after the start of this group. */ + + if (hc >= cd->hwm) + { +@@ -4037,6 +4044,15 @@ + + ptr += 1 + LINK_SIZE; + } ++ ++/* Now adjust all forward reference offsets for the group. */ ++ ++for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm; ++ hc += LINK_SIZE) ++ { ++ offset = (int)GET(hc, 0); ++ PUT(hc, 0, offset + adjust); ++ } + } + + +@@ -4465,7 +4481,7 @@ + const pcre_uchar *nestptr = NULL; + pcre_uchar *previous = NULL; + pcre_uchar *previous_callout = NULL; +-size_t save_hwm_offset = 0; ++size_t item_hwm_offset = 0; + pcre_uint8 classbits[32]; + + /* We can fish out the UTF-8 setting once and for all into a BOOL, but we +@@ -4623,8 +4639,7 @@ + /* In the real compile phase, just check the workspace used by the forward + reference list. */ + +- else if (cd->hwm > cd->start_workspace + cd->workspace_size - +- WORK_SIZE_SAFETY_MARGIN) ++ else if (cd->hwm > cd->start_workspace + cd->workspace_size) + { + *errorcodeptr = ERR52; + goto FAILED; +@@ -4767,6 +4782,7 @@ + zeroreqchar = reqchar; + zeroreqcharflags = reqcharflags; + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY; + break; + +@@ -4818,6 +4834,7 @@ + /* Handle a real character class. */ + + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + + /* PCRE supports POSIX class stuff inside a class. Perl gives an error if + they are encountered at the top level, so we'll do that too. */ +@@ -5195,9 +5212,9 @@ + cd, PRIV(vspace_list)); + continue; + +-#ifdef SUPPORT_UCP + case ESC_p: + case ESC_P: ++#ifdef SUPPORT_UCP + { + BOOL negated; + unsigned int ptype = 0, pdata = 0; +@@ -5211,6 +5228,9 @@ + class_has_8bitchar--; /* Undo! */ + continue; + } ++#else ++ *errorcodeptr = ERR45; ++ goto FAILED; + #endif + /* Unrecognized escapes are faulted if PCRE is running in its + strict mode. By default, for compatibility with Perl, they are +@@ -5930,7 +5950,7 @@ + { + register int i; + int len = (int)(code - previous); +- size_t base_hwm_offset = save_hwm_offset; ++ size_t base_hwm_offset = item_hwm_offset; + pcre_uchar *bralink = NULL; + pcre_uchar *brazeroptr = NULL; + +@@ -5985,7 +6005,7 @@ + if (repeat_max <= 1) /* Covers 0, 1, and unlimited */ + { + *code = OP_END; +- adjust_recurse(previous, 1, utf, cd, save_hwm_offset); ++ adjust_recurse(previous, 1, utf, cd, item_hwm_offset); + memmove(previous + 1, previous, IN_UCHARS(len)); + code++; + if (repeat_max == 0) +@@ -6009,7 +6029,7 @@ + { + int offset; + *code = OP_END; +- adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm_offset); ++ adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, item_hwm_offset); + memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len)); + code += 2 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeat_type; +@@ -6254,6 +6274,12 @@ + while (*scode == OP_ALT); + } + ++ /* A conditional group with only one branch has an implicit empty ++ alternative branch. */ ++ ++ if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT) ++ *bracode = OP_SCOND; ++ + /* Handle possessive quantifiers. */ + + if (possessive_quantifier) +@@ -6267,11 +6293,11 @@ + { + int nlen = (int)(code - bracode); + *code = OP_END; +- adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm_offset); ++ adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, item_hwm_offset); + memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen)); + code += 1 + LINK_SIZE; + nlen += 1 + LINK_SIZE; +- *bracode = OP_BRAPOS; ++ *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS; + *code++ = OP_KETRPOS; + PUTINC(code, 0, nlen); + PUT(bracode, 1, nlen); +@@ -6401,7 +6427,7 @@ + else + { + *code = OP_END; +- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset); ++ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset); + memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len)); + code += 1 + LINK_SIZE; + len += 1 + LINK_SIZE; +@@ -6450,7 +6476,7 @@ + + default: + *code = OP_END; +- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset); ++ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset); + memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len)); + code += 1 + LINK_SIZE; + len += 1 + LINK_SIZE; +@@ -6623,7 +6649,7 @@ + newoptions = options; + skipbytes = 0; + bravalue = OP_CBRA; +- save_hwm_offset = cd->hwm - cd->start_workspace; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + reset_bracount = FALSE; + + /* Deal with the extended parentheses; all are introduced by '?', and the +@@ -6641,6 +6667,7 @@ + /* ------------------------------------------------------------ */ + case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ + reset_bracount = TRUE; ++ cd->dupgroups = TRUE; /* Record (?| encountered */ + /* Fall through */ + + /* ------------------------------------------------------------ */ +@@ -6741,6 +6768,12 @@ + { + while (IS_DIGIT(*ptr)) + { ++ if (recno > INT_MAX / 10 - 1) /* Integer overflow */ ++ { ++ while (IS_DIGIT(*ptr)) ptr++; ++ *errorcodeptr = ERR61; ++ goto FAILED; ++ } + recno = recno * 10 + (int)(*ptr - CHAR_0); + ptr++; + } +@@ -6769,7 +6802,7 @@ + ptr++; + } + namelen = (int)(ptr - name); +- if (lengthptr != NULL) *lengthptr += IMM2_SIZE; ++ if (lengthptr != NULL) skipbytes += IMM2_SIZE; + } + + /* Check the terminator */ +@@ -6875,6 +6908,11 @@ + *errorcodeptr = ERR15; + goto FAILED; + } ++ if (recno > INT_MAX / 10 - 1) /* Integer overflow */ ++ { ++ *errorcodeptr = ERR61; ++ goto FAILED; ++ } + recno = recno * 10 + name[i] - CHAR_0; + } + if (recno == 0) recno = RREF_ANY; +@@ -7151,7 +7189,8 @@ + if (lengthptr != NULL) + { + named_group *ng; +- ++ recno = 0; ++ + if (namelen == 0) + { + *errorcodeptr = ERR62; +@@ -7168,20 +7207,6 @@ + goto FAILED; + } + +- /* The name table does not exist in the first pass; instead we must +- scan the list of names encountered so far in order to get the +- number. If the name is not found, set the value to 0 for a forward +- reference. */ +- +- ng = cd->named_groups; +- for (i = 0; i < cd->names_found; i++, ng++) +- { +- if (namelen == ng->length && +- STRNCMP_UC_UC(name, ng->name, namelen) == 0) +- break; +- } +- recno = (i < cd->names_found)? ng->number : 0; +- + /* Count named back references. */ + + if (!is_recurse) cd->namedrefcount++; +@@ -7191,6 +7216,56 @@ + 16-bit data item. */ + + *lengthptr += IMM2_SIZE; ++ ++ /* If this is a forward reference and we are within a (?|...) group, ++ the reference may end up as the number of a group which we are ++ currently inside, that is, it could be a recursive reference. In the ++ real compile this will be picked up and the reference wrapped with ++ OP_ONCE to make it atomic, so we must space in case this occurs. */ ++ ++ /* In fact, this can happen for a non-forward reference because ++ another group with the same number might be created later. This ++ issue is fixed "properly" in PCRE2. As PCRE1 is now in maintenance ++ only mode, we finesse the bug by allowing more memory always. */ ++ ++ *lengthptr += 2 + 2*LINK_SIZE; ++ ++ /* It is even worse than that. The current reference may be to an ++ existing named group with a different number (so apparently not ++ recursive) but which later on is also attached to a group with the ++ current number. This can only happen if $(| has been previous ++ encountered. In that case, we allow yet more memory, just in case. ++ (Again, this is fixed "properly" in PCRE2. */ ++ ++ if (cd->dupgroups) *lengthptr += 4 + 4*LINK_SIZE; ++ ++ /* Otherwise, check for recursion here. The name table does not exist ++ in the first pass; instead we must scan the list of names encountered ++ so far in order to get the number. If the name is not found, leave ++ the value of recno as 0 for a forward reference. */ ++ ++ else ++ { ++ ng = cd->named_groups; ++ for (i = 0; i < cd->names_found; i++, ng++) ++ { ++ if (namelen == ng->length && ++ STRNCMP_UC_UC(name, ng->name, namelen) == 0) ++ { ++ open_capitem *oc; ++ recno = ng->number; ++ if (is_recurse) break; ++ for (oc = cd->open_caps; oc != NULL; oc = oc->next) ++ { ++ if (oc->number == recno) ++ { ++ oc->flag = TRUE; ++ break; ++ } ++ } ++ } ++ } ++ } + } + + /* In the real compile, search the name table. We check the name +@@ -7237,8 +7312,6 @@ + for (i++; i < cd->names_found; i++) + { + if (STRCMP_UC_UC(slot + IMM2_SIZE, cslot + IMM2_SIZE) != 0) break; +- +- + count++; + cslot += cd->name_entry_size; + } +@@ -7247,6 +7320,7 @@ + { + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = ((options & PCRE_CASELESS) != 0)? OP_DNREFI : OP_DNREF; + PUT2INC(code, 0, index); + PUT2INC(code, 0, count); +@@ -7284,9 +7358,14 @@ + + + /* ------------------------------------------------------------ */ +- case CHAR_R: /* Recursion */ +- ptr++; /* Same as (?0) */ +- /* Fall through */ ++ case CHAR_R: /* Recursion, same as (?0) */ ++ recno = 0; ++ if (*(++ptr) != CHAR_RIGHT_PARENTHESIS) ++ { ++ *errorcodeptr = ERR29; ++ goto FAILED; ++ } ++ goto HANDLE_RECURSION; + + + /* ------------------------------------------------------------ */ +@@ -7323,7 +7402,15 @@ + + recno = 0; + while(IS_DIGIT(*ptr)) ++ { ++ if (recno > INT_MAX / 10 - 1) /* Integer overflow */ ++ { ++ while (IS_DIGIT(*ptr)) ptr++; ++ *errorcodeptr = ERR61; ++ goto FAILED; ++ } + recno = recno * 10 + *ptr++ - CHAR_0; ++ } + + if (*ptr != (pcre_uchar)terminator) + { +@@ -7360,6 +7447,7 @@ + HANDLE_RECURSION: + + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + called = cd->start_code; + + /* When we are actually compiling, find the bracket that is being +@@ -7561,7 +7649,11 @@ + previous = NULL; + cd->iscondassert = FALSE; + } +- else previous = code; ++ else ++ { ++ previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; ++ } + + *code = bravalue; + tempcode = code; +@@ -7809,7 +7901,7 @@ + const pcre_uchar *p; + pcre_uint32 cf; + +- save_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */ ++ item_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */ + terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? + CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; + +@@ -7838,7 +7930,7 @@ + if (*p != (pcre_uchar)terminator) + { + *errorcodeptr = ERR57; +- break; ++ goto FAILED; + } + ptr++; + goto HANDLE_NUMERICAL_RECURSION; +@@ -7853,7 +7945,7 @@ + ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET)) + { + *errorcodeptr = ERR69; +- break; ++ goto FAILED; + } + is_recurse = FALSE; + terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? +@@ -7877,6 +7969,7 @@ + HANDLE_REFERENCE: + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF; + PUT2INC(code, 0, recno); + cd->backref_map |= (recno < 32)? (1 << recno) : 1; +@@ -7906,6 +7999,7 @@ + if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr)) + goto FAILED; + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP; + *code++ = ptype; + *code++ = pdata; +@@ -7946,6 +8040,7 @@ + + { + previous = (escape > ESC_b && escape < ESC_Z)? code : NULL; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape; + } + } +@@ -7989,6 +8084,7 @@ + + ONE_CHAR: + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + + /* For caseless UTF-8 mode when UCP support is available, check whether + this character has more than one other case. If so, generate a special +@@ -9164,6 +9260,7 @@ + cd->name_entry_size = 0; + cd->name_table = NULL; + cd->dupnames = FALSE; ++cd->dupgroups = FALSE; + cd->namedrefcount = 0; + cd->start_code = cworkspace; + cd->hwm = cworkspace; +@@ -9198,7 +9295,7 @@ + + DPRINTF(("end pre-compile: length=%d workspace=%d\n", length, + (int)(cd->hwm - cworkspace))); +- ++ + if (length > MAX_PATTERN_SIZE) + { + errorcode = ERR20; +@@ -9336,6 +9433,16 @@ + int offset, recno; + cd->hwm -= LINK_SIZE; + offset = GET(cd->hwm, 0); ++ ++ /* Check that the hwm handling hasn't gone wrong. This whole area is ++ rewritten in PCRE2 because there are some obscure cases. */ ++ ++ if (offset == 0 || codestart[offset-1] != OP_RECURSE) ++ { ++ errorcode = ERR10; ++ break; ++ } ++ + recno = GET(codestart, offset); + if (recno != prev_recno) + { +@@ -9366,7 +9473,7 @@ + "const" attribute if the cast (pcre_uchar *)codestart is used directly in the + function call. */ + +-if ((options & PCRE_NO_AUTO_POSSESS) == 0) ++if (errorcode == 0 && (options & PCRE_NO_AUTO_POSSESS) == 0) + { + pcre_uchar *temp = (pcre_uchar *)codestart; + auto_possessify(temp, utf, cd); +@@ -9380,7 +9487,7 @@ + exceptional ones forgo this. We scan the pattern to check that they are fixed + length, and set their lengths. */ + +-if (cd->check_lookbehind) ++if (errorcode == 0 && cd->check_lookbehind) + { + pcre_uchar *cc = (pcre_uchar *)codestart; + +@@ -9593,4 +9700,3 @@ + } + + /* End of pcre_compile.c */ +- +Index: ChangeLog +=================================================================== +--- ChangeLog (revision 1554) ++++ ChangeLog (working copy) +@@ -1,6 +1,162 @@ + ChangeLog for PCRE + ------------------ + ++Note that the PCRE 8.xx series (PCRE1) is now in a bugfix-only state. All ++development is happening in the PCRE2 10.xx series. ++ ++Version 8.38 xx-xxx-xxxx ++------------------------ ++ ++1. If a group that contained a recursive back reference also contained a ++ forward reference subroutine call followed by a non-forward-reference ++ subroutine call, for example /.((?2)(?R)\1)()/, pcre2_compile() failed to ++ compile correct code, leading to undefined behaviour or an internally ++ detected error. This bug was discovered by the LLVM fuzzer. ++ ++2. Quantification of certain items (e.g. atomic back references) could cause ++ incorrect code to be compiled when recursive forward references were ++ involved. For example, in this pattern: /(?1)()((((((\1++))\x85)+)|))/. ++ This bug was discovered by the LLVM fuzzer. ++ ++3. A repeated conditional group whose condition was a reference by name caused ++ a buffer overflow if there was more than one group with the given name. ++ This bug was discovered by the LLVM fuzzer. ++ ++4. A recursive back reference by name within a group that had the same name as ++ another group caused a buffer overflow. For example: ++ /(?J)(?'d'(?'d'\g{d}))/. This bug was discovered by the LLVM fuzzer. ++ ++5. A forward reference by name to a group whose number is the same as the ++ current group, for example in this pattern: /(?|(\k'Pm')|(?'Pm'))/, caused ++ a buffer overflow at compile time. This bug was discovered by the LLVM ++ fuzzer. ++ ++6. A lookbehind assertion within a set of mutually recursive subpatterns could ++ provoke a buffer overflow. This bug was discovered by the LLVM fuzzer. ++ ++7. Another buffer overflow bug involved duplicate named groups with a ++ reference between their definition, with a group that reset capture ++ numbers, for example: /(?J:(?|(?'R')(\k'R')|((?'R'))))/. This has been ++ fixed by always allowing for more memory, even if not needed. (A proper fix ++ is implemented in PCRE2, but it involves more refactoring.) ++ ++8. There was no check for integer overflow in subroutine calls such as (?123). ++ ++9. The table entry for \l in EBCDIC environments was incorrect, leading to its ++ being treated as a literal 'l' instead of causing an error. ++ ++10. There was a buffer overflow if pcre_exec() was called with an ovector of ++ size 1. This bug was found by american fuzzy lop. ++ ++11. If a non-capturing group containing a conditional group that could match ++ an empty string was repeated, it was not identified as matching an empty ++ string itself. For example: /^(?:(?(1)x|)+)+$()/. ++ ++12. In an EBCDIC environment, pcretest was mishandling the escape sequences ++ \a and \e in test subject lines. ++ ++13. In an EBCDIC environment, \a in a pattern was converted to the ASCII ++ instead of the EBCDIC value. ++ ++14. The handling of \c in an EBCDIC environment has been revised so that it is ++ now compatible with the specification in Perl's perlebcdic page. ++ ++15. The EBCDIC character 0x41 is a non-breaking space, equivalent to 0xa0 in ++ ASCII/Unicode. This has now been added to the list of characters that are ++ recognized as white space in EBCDIC. ++ ++16. When PCRE was compiled without UCP support, the use of \p and \P gave an ++ error (correctly) when used outside a class, but did not give an error ++ within a class. ++ ++17. \h within a class was incorrectly compiled in EBCDIC environments. ++ ++18. A pattern with an unmatched closing parenthesis that contained a backward ++ assertion which itself contained a forward reference caused buffer ++ overflow. And example pattern is: /(?=di(?<=(?1))|(?=(.))))/. ++ ++19. JIT should return with error when the compiled pattern requires more stack ++ space than the maximum. ++ ++20. A possessively repeated conditional group that could match an empty string, ++ for example, /(?(R))*+/, was incorrectly compiled. ++ ++21. Fix infinite recursion in the JIT compiler when certain patterns such as ++ /(?:|a|){100}x/ are analysed. ++ ++22. Some patterns with character classes involving [: and \\ were incorrectly ++ compiled and could cause reading from uninitialized memory or an incorrect ++ error diagnosis. ++ ++23. Pathological patterns containing many nested occurrences of [: caused ++ pcre_compile() to run for a very long time. ++ ++24. A conditional group with only one branch has an implicit empty alternative ++ branch and must therefore be treated as potentially matching an empty ++ string. ++ ++25. If (?R was followed by - or + incorrect behaviour happened instead of a ++ diagnostic. ++ ++26. Arrange to give up on finding the minimum matching length for overly ++ complex patterns. ++ ++27. Similar to (4) above: in a pattern with duplicated named groups and an ++ occurrence of (?| it is possible for an apparently non-recursive back ++ reference to become recursive if a later named group with the relevant ++ number is encountered. This could lead to a buffer overflow. Wen Guanxing ++ from Venustech ADLAB discovered this bug. ++ ++28. If pcregrep was given the -q option with -c or -l, or when handling a ++ binary file, it incorrectly wrote output to stdout. ++ ++29. The JIT compiler did not restore the control verb head in case of *THEN ++ control verbs. This issue was found by Karl Skomski with a custom LLVM ++ fuzzer. ++ ++30. Error messages for syntax errors following \g and \k were giving inaccurate ++ offsets in the pattern. ++ ++31. Added a check for integer overflow in conditions (?() and ++ (?(R). This omission was discovered by Karl Skomski with the LLVM ++ fuzzer. ++ ++32. Handling recursive references such as (?2) when the reference is to a group ++ later in the pattern uses code that is very hacked about and error-prone. ++ It has been re-written for PCRE2. Here in PCRE1, a check has been added to ++ give an internal error if it is obvious that compiling has gone wrong. ++ ++33. The JIT compiler should not check repeats after a {0,1} repeat byte code. ++ This issue was found by Karl Skomski with a custom LLVM fuzzer. ++ ++34. The JIT compiler should restore the control chain for empty possessive ++ repeats. This issue was found by Karl Skomski with a custom LLVM fuzzer. ++ ++35. Match limit check added to JIT recursion. This issue was found by Karl ++ Skomski with a custom LLVM fuzzer. ++ ++36. Yet another case similar to 27 above has been circumvented by an ++ unconditional allocation of extra memory. This issue is fixed "properly" in ++ PCRE2 by refactoring the way references are handled. Wen Guanxing ++ from Venustech ADLAB discovered this bug. ++ ++37. Fix two assertion fails in JIT. These issues were found by Karl Skomski ++ with a custom LLVM fuzzer. ++ ++38. Fixed a corner case of range optimization in JIT. ++ ++39. An incorrect error "overran compiling workspace" was given if there were ++ exactly enough group forward references such that the last one extended ++ into the workspace safety margin. The next one would have expanded the ++ workspace. The test for overflow was not including the safety margin. ++ ++40. A match limit issue is fixed in JIT which was found by Karl Skomski ++ with a custom LLVM fuzzer. ++ ++41. Remove the use of /dev/null in testdata/testinput2, because it doesn't ++ work under Windows. (Why has it taken so long for anyone to notice?) ++ ++ + Version 8.37 28-April-2015 + -------------------------- + +Index: pcretest.c +=================================================================== +--- pcretest.c (revision 1554) ++++ pcretest.c (working copy) +@@ -4621,9 +4621,9 @@ + + else switch ((c = *p++)) + { +- case 'a': c = 7; break; ++ case 'a': c = CHAR_BEL; break; + case 'b': c = '\b'; break; +- case 'e': c = 27; break; ++ case 'e': c = CHAR_ESC; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; +Index: sljit/sljitLir.c +=================================================================== +--- sljit/sljitLir.c (revision 1554) ++++ sljit/sljitLir.c (working copy) +@@ -845,8 +845,8 @@ + } + + static SLJIT_CONST char* op0_names[] = { +- (char*)"breakpoint", (char*)"nop", +- (char*)"lumul", (char*)"lsmul", (char*)"ludiv", (char*)"lsdiv", ++ (char*)"breakpoint", (char*)"nop", (char*)"lumul", (char*)"lsmul", ++ (char*)"udivmod", (char*)"sdivmod", (char*)"udivi", (char*)"sdivi" + }; + + static SLJIT_CONST char* op1_names[] = { +@@ -1036,7 +1036,7 @@ + { + #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) + CHECK_ARGUMENT((op >= SLJIT_BREAKPOINT && op <= SLJIT_LSMUL) +- || ((op & ~SLJIT_INT_OP) >= SLJIT_LUDIV && (op & ~SLJIT_INT_OP) <= SLJIT_LSDIV)); ++ || ((op & ~SLJIT_INT_OP) >= SLJIT_UDIVMOD && (op & ~SLJIT_INT_OP) <= SLJIT_SDIVI)); + CHECK_ARGUMENT(op < SLJIT_LUMUL || compiler->scratches >= 2); + #endif + #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) +@@ -1447,6 +1447,8 @@ + + static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset) + { ++ SLJIT_UNUSED_ARG(offset); ++ + #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) + FUNCTION_CHECK_DST(dst, dstw); + #endif +@@ -1462,6 +1464,8 @@ + + static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value) + { ++ SLJIT_UNUSED_ARG(init_value); ++ + #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) + FUNCTION_CHECK_DST(dst, dstw); + #endif +Index: sljit/sljitNativeSPARC_common.c +=================================================================== +--- sljit/sljitNativeSPARC_common.c (revision 1554) ++++ sljit/sljitNativeSPARC_common.c (working copy) +@@ -777,20 +777,25 @@ + #else + #error "Implementation required" + #endif +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); + #if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) +- if (op == SLJIT_LUDIV) ++ if ((op | 0x2) == SLJIT_UDIVI) + FAIL_IF(push_inst(compiler, WRY | S1(0), MOVABLE_INS)); + else { + FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(SLJIT_R0) | IMM(31), DR(TMP_REG1))); + FAIL_IF(push_inst(compiler, WRY | S1(TMP_REG1), MOVABLE_INS)); + } +- FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_R0), DR(TMP_REG2))); +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0))); ++ if (op <= SLJIT_SDIVMOD) ++ FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_R0), DR(TMP_REG2))); ++ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0))); ++ if (op >= SLJIT_UDIVI) ++ return SLJIT_SUCCESS; + FAIL_IF(push_inst(compiler, SMUL | D(SLJIT_R1) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R1))); +- FAIL_IF(push_inst(compiler, SUB | D(SLJIT_R1) | S1(TMP_REG2) | S2(SLJIT_R1), DR(SLJIT_R1))); +- return SLJIT_SUCCESS; ++ return push_inst(compiler, SUB | D(SLJIT_R1) | S1(TMP_REG2) | S2(SLJIT_R1), DR(SLJIT_R1)); + #else + #error "Implementation required" + #endif +Index: sljit/sljitNativeMIPS_common.c +=================================================================== +--- sljit/sljitNativeMIPS_common.c (revision 1554) ++++ sljit/sljitNativeMIPS_common.c (working copy) +@@ -1053,8 +1053,11 @@ + #endif + FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0))); + return push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1)); +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); + #if !(defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1) + FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); + FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); +@@ -1062,15 +1065,15 @@ + + #if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) + if (int_op) +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); ++ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); + else +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); ++ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); + #else +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); ++ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); + #endif + + FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0))); +- return push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1)); ++ return (op >= SLJIT_UDIVI) ? SLJIT_SUCCESS : push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1)); + } + + return SLJIT_SUCCESS; +Index: sljit/sljitNativeARM_32.c +=================================================================== +--- sljit/sljitNativeARM_32.c (revision 1554) ++++ sljit/sljitNativeARM_32.c (working copy) +@@ -1833,18 +1833,33 @@ + | (reg_map[SLJIT_R0] << 8) + | reg_map[TMP_REG1]); + #endif +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: +- if (compiler->scratches >= 3) ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); ++ SLJIT_COMPILE_ASSERT(reg_map[2] == 1 && reg_map[3] == 2, bad_register_mapping); ++ ++ if ((op >= SLJIT_UDIVI) && (compiler->scratches >= 3)) { + FAIL_IF(push_inst(compiler, 0xe52d2008 /* str r2, [sp, #-8]! */)); ++ FAIL_IF(push_inst(compiler, 0xe58d1004 /* str r1, [sp, #4] */)); ++ } ++ else if ((op >= SLJIT_UDIVI) || (compiler->scratches >= 3)) ++ FAIL_IF(push_inst(compiler, 0xe52d0008 | (op >= SLJIT_UDIVI ? 0x1000 : 0x2000) /* str r1/r2, [sp, #-8]! */)); ++ + #if defined(__GNUC__) + FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, +- (op == SLJIT_LUDIV ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); ++ ((op | 0x2) == SLJIT_UDIVI ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); + #else + #error "Software divmod functions are needed" + #endif +- if (compiler->scratches >= 3) +- return push_inst(compiler, 0xe49d2008 /* ldr r2, [sp], #8 */); ++ ++ if ((op >= SLJIT_UDIVI) && (compiler->scratches >= 3)) { ++ FAIL_IF(push_inst(compiler, 0xe59d1004 /* ldr r1, [sp, #4] */)); ++ FAIL_IF(push_inst(compiler, 0xe49d2008 /* ldr r2, [sp], #8 */)); ++ } ++ else if ((op >= SLJIT_UDIVI) || (compiler->scratches >= 3)) ++ return push_inst(compiler, 0xe49d0008 | (op >= SLJIT_UDIVI ? 0x1000 : 0x2000) /* ldr r1/r2, [sp], #8 */); + return SLJIT_SUCCESS; + } + +Index: sljit/sljitLir.h +=================================================================== +--- sljit/sljitLir.h (revision 1554) ++++ sljit/sljitLir.h (working copy) +@@ -687,7 +687,7 @@ + #define SLJIT_OP0_BASE 0 + + /* Flags: - (never set any flags) +- Note: breakpoint instruction is not supported by all architectures (namely ppc) ++ Note: breakpoint instruction is not supported by all architectures (e.g. ppc) + It falls back to SLJIT_NOP in those cases. */ + #define SLJIT_BREAKPOINT (SLJIT_OP0_BASE + 0) + /* Flags: - (never set any flags) +@@ -696,24 +696,42 @@ + #define SLJIT_NOP (SLJIT_OP0_BASE + 1) + /* Flags: - (may destroy flags) + Unsigned multiplication of SLJIT_R0 and SLJIT_R1. +- Result goes to SLJIT_R1:SLJIT_R0 (high:low) word */ ++ Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */ + #define SLJIT_LUMUL (SLJIT_OP0_BASE + 2) + /* Flags: - (may destroy flags) + Signed multiplication of SLJIT_R0 and SLJIT_R1. +- Result goes to SLJIT_R1:SLJIT_R0 (high:low) word */ ++ Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */ + #define SLJIT_LSMUL (SLJIT_OP0_BASE + 3) + /* Flags: I - (may destroy flags) + Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1. +- The result is placed in SLJIT_R0 and the remainder goes to SLJIT_R1. +- Note: if SLJIT_R1 contains 0, the behaviour is undefined. */ +-#define SLJIT_LUDIV (SLJIT_OP0_BASE + 4) +-#define SLJIT_ILUDIV (SLJIT_LUDIV | SLJIT_INT_OP) ++ The result is placed into SLJIT_R0 and the remainder into SLJIT_R1. ++ Note: if SLJIT_R1 is 0, the behaviour is undefined. */ ++#define SLJIT_UDIVMOD (SLJIT_OP0_BASE + 4) ++#define SLJIT_IUDIVMOD (SLJIT_UDIVMOD | SLJIT_INT_OP) + /* Flags: I - (may destroy flags) + Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1. +- The result is placed in SLJIT_R0 and the remainder goes to SLJIT_R1. +- Note: if SLJIT_R1 contains 0, the behaviour is undefined. */ +-#define SLJIT_LSDIV (SLJIT_OP0_BASE + 5) +-#define SLJIT_ILSDIV (SLJIT_LSDIV | SLJIT_INT_OP) ++ The result is placed into SLJIT_R0 and the remainder into SLJIT_R1. ++ Note: if SLJIT_R1 is 0, the behaviour is undefined. ++ Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00), ++ the behaviour is undefined. */ ++#define SLJIT_SDIVMOD (SLJIT_OP0_BASE + 5) ++#define SLJIT_ISDIVMOD (SLJIT_SDIVMOD | SLJIT_INT_OP) ++/* Flags: I - (may destroy flags) ++ Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1. ++ The result is placed into SLJIT_R0. SLJIT_R1 preserves its value. ++ Note: if SLJIT_R1 is 0, the behaviour is undefined. ++ Note: SLJIT_SDIV is single precision divide. */ ++#define SLJIT_UDIVI (SLJIT_OP0_BASE + 6) ++#define SLJIT_IUDIVI (SLJIT_UDIVI | SLJIT_INT_OP) ++/* Flags: I - (may destroy flags) ++ Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1. ++ The result is placed into SLJIT_R0. SLJIT_R1 preserves its value. ++ Note: if SLJIT_R1 is 0, the behaviour is undefined. ++ Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00), ++ the behaviour is undefined. ++ Note: SLJIT_SDIV is single precision divide. */ ++#define SLJIT_SDIVI (SLJIT_OP0_BASE + 7) ++#define SLJIT_ISDIVI (SLJIT_SDIVI | SLJIT_INT_OP) + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op); + +@@ -851,34 +869,6 @@ + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w); + +-/* The following function is a helper function for sljit_emit_op_custom. +- It returns with the real machine register index ( >=0 ) of any SLJIT_R, +- SLJIT_S and SLJIT_SP registers. +- +- Note: it returns with -1 for virtual registers (only on x86-32). */ +- +-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg); +- +-/* The following function is a helper function for sljit_emit_op_custom. +- It returns with the real machine register index of any SLJIT_FLOAT register. +- +- Note: the index is always an even number on ARM (except ARM-64), MIPS, and SPARC. */ +- +-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg); +- +-/* Any instruction can be inserted into the instruction stream by +- sljit_emit_op_custom. It has a similar purpose as inline assembly. +- The size parameter must match to the instruction size of the target +- architecture: +- +- x86: 0 < size <= 15. The instruction argument can be byte aligned. +- Thumb2: if size == 2, the instruction argument must be 2 byte aligned. +- if size == 4, the instruction argument must be 4 byte aligned. +- Otherwise: size must be 4 and instruction argument must be 4 byte aligned. */ +- +-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, +- void *instruction, sljit_si size); +- + /* Returns with non-zero if fpu is available. */ + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void); +@@ -1196,4 +1186,64 @@ + + #endif /* !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) */ + ++/* --------------------------------------------------------------------- */ ++/* CPU specific functions */ ++/* --------------------------------------------------------------------- */ ++ ++/* The following function is a helper function for sljit_emit_op_custom. ++ It returns with the real machine register index ( >=0 ) of any SLJIT_R, ++ SLJIT_S and SLJIT_SP registers. ++ ++ Note: it returns with -1 for virtual registers (only on x86-32). */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg); ++ ++/* The following function is a helper function for sljit_emit_op_custom. ++ It returns with the real machine register index of any SLJIT_FLOAT register. ++ ++ Note: the index is always an even number on ARM (except ARM-64), MIPS, and SPARC. */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg); ++ ++/* Any instruction can be inserted into the instruction stream by ++ sljit_emit_op_custom. It has a similar purpose as inline assembly. ++ The size parameter must match to the instruction size of the target ++ architecture: ++ ++ x86: 0 < size <= 15. The instruction argument can be byte aligned. ++ Thumb2: if size == 2, the instruction argument must be 2 byte aligned. ++ if size == 4, the instruction argument must be 4 byte aligned. ++ Otherwise: size must be 4 and instruction argument must be 4 byte aligned. */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, ++ void *instruction, sljit_si size); ++ ++#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) ++ ++/* Returns with non-zero if sse2 is available. */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_sse2_available(void); ++ ++/* Returns with non-zero if cmov instruction is available. */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_cmov_available(void); ++ ++/* Emit a conditional mov instruction on x86 CPUs. This instruction ++ moves src to destination, if the condition is satisfied. Unlike ++ other arithmetic instructions, destination must be a register. ++ Before such instructions are emitted, cmov support should be ++ checked by sljit_x86_is_cmov_available function. ++ type must be between SLJIT_EQUAL and SLJIT_S_ORDERED ++ dst_reg must be a valid register and it can be combined ++ with SLJIT_INT_OP to perform 32 bit arithmetic ++ Flags: I - (never set any flags) ++ */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_emit_cmov(struct sljit_compiler *compiler, ++ sljit_si type, ++ sljit_si dst_reg, ++ sljit_si src, sljit_sw srcw); ++ ++#endif ++ + #endif /* _SLJIT_LIR_H_ */ +Index: sljit/sljitNativeARM_64.c +=================================================================== +--- sljit/sljitNativeARM_64.c (revision 1554) ++++ sljit/sljitNativeARM_64.c (working copy) +@@ -1087,7 +1087,8 @@ + saved_regs_size += sizeof(sljit_sw); + } + local_size -= saved_regs_size + SLJIT_LOCALS_OFFSET; +- FAIL_IF(push_inst(compiler, SUBI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10))); ++ if (saved_regs_size > 0) ++ FAIL_IF(push_inst(compiler, SUBI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10))); + } + + tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG; +@@ -1094,7 +1095,12 @@ + prev = -1; + for (i = SLJIT_S0; i >= tmp; i--) { + if (prev == -1) { +- prev = i; ++ if (!(offs & (1 << 15))) { ++ prev = i; ++ continue; ++ } ++ FAIL_IF(push_inst(compiler, STRI | RT(i) | RN(TMP_SP) | (offs >> 5))); ++ offs += 1 << 15; + continue; + } + FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(TMP_SP) | offs)); +@@ -1104,7 +1110,12 @@ + + for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { + if (prev == -1) { +- prev = i; ++ if (!(offs & (1 << 15))) { ++ prev = i; ++ continue; ++ } ++ FAIL_IF(push_inst(compiler, STRI | RT(i) | RN(TMP_SP) | (offs >> 5))); ++ offs += 1 << 15; + continue; + } + FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(TMP_SP) | offs)); +@@ -1112,8 +1123,7 @@ + prev = -1; + } + +- if (prev != -1) +- FAIL_IF(push_inst(compiler, STRI | RT(prev) | RN(TMP_SP) | (offs >> 5))); ++ SLJIT_ASSERT(prev == -1); + + if (compiler->local_size > (63 * sizeof(sljit_sw))) { + /* The local_size is already adjusted by the saved registers. */ +@@ -1188,7 +1198,12 @@ + prev = -1; + for (i = SLJIT_S0; i >= tmp; i--) { + if (prev == -1) { +- prev = i; ++ if (!(offs & (1 << 15))) { ++ prev = i; ++ continue; ++ } ++ FAIL_IF(push_inst(compiler, LDRI | RT(i) | RN(TMP_SP) | (offs >> 5))); ++ offs += 1 << 15; + continue; + } + FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(TMP_SP) | offs)); +@@ -1198,7 +1213,12 @@ + + for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { + if (prev == -1) { +- prev = i; ++ if (!(offs & (1 << 15))) { ++ prev = i; ++ continue; ++ } ++ FAIL_IF(push_inst(compiler, LDRI | RT(i) | RN(TMP_SP) | (offs >> 5))); ++ offs += 1 << 15; + continue; + } + FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(TMP_SP) | offs)); +@@ -1206,13 +1226,12 @@ + prev = -1; + } + +- if (prev != -1) +- FAIL_IF(push_inst(compiler, LDRI | RT(prev) | RN(TMP_SP) | (offs >> 5))); ++ SLJIT_ASSERT(prev == -1); + + if (compiler->local_size <= (63 * sizeof(sljit_sw))) { + FAIL_IF(push_inst(compiler, LDP_PST | 29 | RT2(TMP_LR) + | RN(TMP_SP) | (((local_size >> 3) & 0x7f) << 15))); +- } else { ++ } else if (saved_regs_size > 0) { + FAIL_IF(push_inst(compiler, ADDI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10))); + } + +@@ -1242,12 +1261,15 @@ + FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0))); + FAIL_IF(push_inst(compiler, MADD | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO))); + return push_inst(compiler, (op == SLJIT_LUMUL ? UMULH : SMULH) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1)); +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: + FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0))); +- FAIL_IF(push_inst(compiler, ((op == SLJIT_LUDIV ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1))); ++ FAIL_IF(push_inst(compiler, ((op == SLJIT_UDIVMOD ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1))); + FAIL_IF(push_inst(compiler, (MADD ^ inv_bits) | RD(SLJIT_R1) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO))); + return push_inst(compiler, (SUB ^ inv_bits) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1)); ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ return push_inst(compiler, ((op == SLJIT_UDIVI ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1)); + } + + return SLJIT_SUCCESS; +Index: sljit/sljitNativeARM_T2_32.c +=================================================================== +--- sljit/sljitNativeARM_T2_32.c (revision 1554) ++++ sljit/sljitNativeARM_T2_32.c (working copy) +@@ -1239,6 +1239,9 @@ + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) + { ++ sljit_sw saved_reg_list[3]; ++ sljit_sw saved_reg_count; ++ + CHECK_ERROR(); + CHECK(check_sljit_emit_op0(compiler, op)); + +@@ -1255,24 +1258,53 @@ + | (reg_map[SLJIT_R0] << 12) + | (reg_map[SLJIT_R0] << 16) + | reg_map[SLJIT_R1]); +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: +- if (compiler->scratches >= 4) { +- FAIL_IF(push_inst32(compiler, 0xf84d2d04 /* str r2, [sp, #-4]! */)); +- FAIL_IF(push_inst32(compiler, 0xf84dcd04 /* str ip, [sp, #-4]! */)); +- } else if (compiler->scratches >= 3) +- FAIL_IF(push_inst32(compiler, 0xf84d2d08 /* str r2, [sp, #-8]! */)); ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); ++ SLJIT_COMPILE_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 12, bad_register_mapping); ++ ++ saved_reg_count = 0; ++ if (compiler->scratches >= 4) ++ saved_reg_list[saved_reg_count++] = 12; ++ if (compiler->scratches >= 3) ++ saved_reg_list[saved_reg_count++] = 2; ++ if (op >= SLJIT_UDIVI) ++ saved_reg_list[saved_reg_count++] = 1; ++ ++ if (saved_reg_count > 0) { ++ FAIL_IF(push_inst32(compiler, 0xf84d0d00 | (saved_reg_count >= 3 ? 16 : 8) ++ | (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */)); ++ if (saved_reg_count >= 2) { ++ SLJIT_ASSERT(saved_reg_list[1] < 8); ++ FAIL_IF(push_inst16(compiler, 0x9001 | (saved_reg_list[1] << 8) /* str rX, [sp, #4] */)); ++ } ++ if (saved_reg_count >= 3) { ++ SLJIT_ASSERT(saved_reg_list[2] < 8); ++ FAIL_IF(push_inst16(compiler, 0x9002 | (saved_reg_list[2] << 8) /* str rX, [sp, #8] */)); ++ } ++ } ++ + #if defined(__GNUC__) + FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, +- (op == SLJIT_LUDIV ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); ++ ((op | 0x2) == SLJIT_UDIVI ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); + #else + #error "Software divmod functions are needed" + #endif +- if (compiler->scratches >= 4) { +- FAIL_IF(push_inst32(compiler, 0xf85dcb04 /* ldr ip, [sp], #4 */)); +- return push_inst32(compiler, 0xf85d2b04 /* ldr r2, [sp], #4 */); +- } else if (compiler->scratches >= 3) +- return push_inst32(compiler, 0xf85d2b08 /* ldr r2, [sp], #8 */); ++ ++ if (saved_reg_count > 0) { ++ if (saved_reg_count >= 3) { ++ SLJIT_ASSERT(saved_reg_list[2] < 8); ++ FAIL_IF(push_inst16(compiler, 0x9802 | (saved_reg_list[2] << 8) /* ldr rX, [sp, #8] */)); ++ } ++ if (saved_reg_count >= 2) { ++ SLJIT_ASSERT(saved_reg_list[1] < 8); ++ FAIL_IF(push_inst16(compiler, 0x9801 | (saved_reg_list[1] << 8) /* ldr rX, [sp, #4] */)); ++ } ++ return push_inst32(compiler, 0xf85d0b00 | (saved_reg_count >= 3 ? 16 : 8) ++ | (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */); ++ } + return SLJIT_SUCCESS; + } + +Index: sljit/sljitNativePPC_common.c +=================================================================== +--- sljit/sljitNativePPC_common.c (revision 1554) ++++ sljit/sljitNativePPC_common.c (working copy) +@@ -1267,22 +1267,23 @@ + FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); + return push_inst(compiler, (op == SLJIT_LUMUL ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1)); + #endif +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: + FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0))); + #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) +- if (int_op) { +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVWU : DIVW) | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); +- FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); +- } else { +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVDU : DIVD) | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); +- FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); +- } +- return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1)); ++ FAIL_IF(push_inst(compiler, (int_op ? (op == SLJIT_UDIVMOD ? DIVWU : DIVW) : (op == SLJIT_UDIVMOD ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1))); ++ FAIL_IF(push_inst(compiler, (int_op ? MULLW : MULLD) | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); + #else +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVWU : DIVW) | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); ++ FAIL_IF(push_inst(compiler, (op == SLJIT_UDIVMOD ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1))); + FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); ++#endif + return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1)); ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) ++ return push_inst(compiler, (int_op ? (op == SLJIT_UDIVI ? DIVWU : DIVW) : (op == SLJIT_UDIVI ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)); ++#else ++ return push_inst(compiler, (op == SLJIT_UDIVI ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)); + #endif + } + +Index: sljit/sljitNativeX86_common.c +=================================================================== +--- sljit/sljitNativeX86_common.c (revision 1554) ++++ sljit/sljitNativeX86_common.c (working copy) +@@ -273,7 +273,9 @@ + #endif + static sljit_si cpu_has_cmov = -1; + +-#if defined(_MSC_VER) && _MSC_VER >= 1400 ++#ifdef _WIN32_WCE ++#include ++#elif defined(_MSC_VER) && _MSC_VER >= 1400 + #include + #endif + +@@ -742,8 +744,10 @@ + break; + case SLJIT_LUMUL: + case SLJIT_LSMUL: +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: + compiler->flags_saved = 0; + #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + #ifdef _WIN64 +@@ -761,9 +765,10 @@ + #endif + compiler->mode32 = op & SLJIT_INT_OP; + #endif ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); + + op = GET_OPCODE(op); +- if (op == SLJIT_LUDIV) { ++ if ((op | 0x2) == SLJIT_UDIVI) { + #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) + EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0); + inst = emit_x86_instruction(compiler, 1, SLJIT_R1, 0, SLJIT_R1, 0); +@@ -774,7 +779,7 @@ + *inst = XOR_r_rm; + } + +- if (op == SLJIT_LSDIV) { ++ if ((op | 0x2) == SLJIT_SDIVI) { + #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) + EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0); + #endif +@@ -805,10 +810,10 @@ + FAIL_IF(!inst); + INC_SIZE(2); + *inst++ = GROUP_F7; +- *inst = MOD_REG | ((op >= SLJIT_LUDIV) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]); ++ *inst = MOD_REG | ((op >= SLJIT_UDIVMOD) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]); + #else + #ifdef _WIN64 +- size = (!compiler->mode32 || op >= SLJIT_LUDIV) ? 3 : 2; ++ size = (!compiler->mode32 || op >= SLJIT_UDIVMOD) ? 3 : 2; + #else + size = (!compiler->mode32) ? 3 : 2; + #endif +@@ -817,11 +822,11 @@ + INC_SIZE(size); + #ifdef _WIN64 + if (!compiler->mode32) +- *inst++ = REX_W | ((op >= SLJIT_LUDIV) ? REX_B : 0); +- else if (op >= SLJIT_LUDIV) ++ *inst++ = REX_W | ((op >= SLJIT_UDIVMOD) ? REX_B : 0); ++ else if (op >= SLJIT_UDIVMOD) + *inst++ = REX_B; + *inst++ = GROUP_F7; +- *inst = MOD_REG | ((op >= SLJIT_LUDIV) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]); ++ *inst = MOD_REG | ((op >= SLJIT_UDIVMOD) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]); + #else + if (!compiler->mode32) + *inst++ = REX_W; +@@ -836,15 +841,21 @@ + case SLJIT_LSMUL: + *inst |= IMUL; + break; +- case SLJIT_LUDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_UDIVI: + *inst |= DIV; + break; +- case SLJIT_LSDIV: ++ case SLJIT_SDIVMOD: ++ case SLJIT_SDIVI: + *inst |= IDIV; + break; + } + #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64) +- EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0); ++ if (op <= SLJIT_SDIVMOD) ++ EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0); ++#else ++ if (op >= SLJIT_UDIVI) ++ EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0); + #endif + break; + } +@@ -1905,60 +1916,62 @@ + return SLJIT_SUCCESS; + } + +- if (FAST_IS_REG(src1)) { ++ if (!(src1 & SLJIT_IMM)) { + if (src2 & SLJIT_IMM) { + #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (IS_HALFWORD(src2w) || compiler->mode32) { +- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0); ++ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w); + FAIL_IF(!inst); + *inst = GROUP_F7; + } + else { + FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w)); +- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src1, 0); ++ inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src1, src1w); + FAIL_IF(!inst); + *inst = TEST_rm_r; + } + #else +- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0); ++ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w); + FAIL_IF(!inst); + *inst = GROUP_F7; + #endif ++ return SLJIT_SUCCESS; + } +- else { ++ else if (FAST_IS_REG(src1)) { + inst = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w); + FAIL_IF(!inst); + *inst = TEST_rm_r; ++ return SLJIT_SUCCESS; + } +- return SLJIT_SUCCESS; + } + +- if (FAST_IS_REG(src2)) { ++ if (!(src2 & SLJIT_IMM)) { + if (src1 & SLJIT_IMM) { + #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (IS_HALFWORD(src1w) || compiler->mode32) { +- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, 0); ++ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, src2w); + FAIL_IF(!inst); + *inst = GROUP_F7; + } + else { + FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src1w)); +- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src2, 0); ++ inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src2, src2w); + FAIL_IF(!inst); + *inst = TEST_rm_r; + } + #else +- inst = emit_x86_instruction(compiler, 1, src1, src1w, src2, 0); ++ inst = emit_x86_instruction(compiler, 1, src1, src1w, src2, src2w); + FAIL_IF(!inst); + *inst = GROUP_F7; + #endif ++ return SLJIT_SUCCESS; + } +- else { ++ else if (FAST_IS_REG(src2)) { + inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w); + FAIL_IF(!inst); + *inst = TEST_rm_r; ++ return SLJIT_SUCCESS; + } +- return SLJIT_SUCCESS; + } + + EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); +@@ -2923,3 +2936,69 @@ + { + *(sljit_sw*)addr = new_constant; + } ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_sse2_available(void) ++{ ++#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) ++ if (cpu_has_sse2 == -1) ++ get_cpu_features(); ++ return cpu_has_sse2; ++#else ++ return 1; ++#endif ++} ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_cmov_available(void) ++{ ++ if (cpu_has_cmov == -1) ++ get_cpu_features(); ++ return cpu_has_cmov; ++} ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_emit_cmov(struct sljit_compiler *compiler, ++ sljit_si type, ++ sljit_si dst_reg, ++ sljit_si src, sljit_sw srcw) ++{ ++ sljit_ub* inst; ++ ++ CHECK_ERROR(); ++#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) ++ CHECK_ARGUMENT(sljit_x86_is_cmov_available()); ++ CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_INT_OP))); ++ CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_D_ORDERED); ++ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg & ~SLJIT_INT_OP)); ++ FUNCTION_CHECK_SRC(src, srcw); ++#endif ++#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) ++ if (SLJIT_UNLIKELY(!!compiler->verbose)) { ++ fprintf(compiler->verbose, " x86_cmov%s %s%s, ", ++ !(dst_reg & SLJIT_INT_OP) ? "" : ".i", ++ JUMP_PREFIX(type), jump_names[type & 0xff]); ++ sljit_verbose_reg(compiler, dst_reg & ~SLJIT_INT_OP); ++ fprintf(compiler->verbose, ", "); ++ sljit_verbose_param(compiler, src, srcw); ++ fprintf(compiler->verbose, "\n"); ++ } ++#endif ++ ++ ADJUST_LOCAL_OFFSET(src, srcw); ++ CHECK_EXTRA_REGS(src, srcw, (void)0); ++ ++#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) ++ compiler->mode32 = dst_reg & SLJIT_INT_OP; ++#endif ++ dst_reg &= ~SLJIT_INT_OP; ++ ++ if (SLJIT_UNLIKELY(src & SLJIT_IMM)) { ++ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcw); ++ src = TMP_REG1; ++ srcw = 0; ++ } ++ ++ inst = emit_x86_instruction(compiler, 2, dst_reg, 0, src, srcw); ++ FAIL_IF(!inst); ++ *inst++ = GROUP_0F; ++ *inst = get_jump_code(type & 0xff) - 0x40; ++ return SLJIT_SUCCESS; ++} +Index: sljit/sljitConfigInternal.h +=================================================================== +--- sljit/sljitConfigInternal.h (revision 1554) ++++ sljit/sljitConfigInternal.h (working copy) +@@ -468,8 +468,13 @@ + + #ifndef SLJIT_CALL + +-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) ++#if (defined SLJIT_USE_CDECL_CALLING_CONVENTION && SLJIT_USE_CDECL_CALLING_CONVENTION) + ++/* Force cdecl. */ ++#define SLJIT_CALL ++ ++#elif (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) ++ + #if defined(__GNUC__) && !defined(__APPLE__) + + #define SLJIT_CALL __attribute__ ((fastcall)) +@@ -608,6 +613,12 @@ + #define SLJIT_LOCALS_OFFSET_BASE ((23 + 1) * sizeof(sljit_sw)) + #endif + ++#elif (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) ++ ++#define SLJIT_NUMBER_OF_REGISTERS 10 ++#define SLJIT_NUMBER_OF_SAVED_REGISTERS 5 ++#define SLJIT_LOCALS_OFFSET_BASE 0 ++ + #elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) + + #define SLJIT_NUMBER_OF_REGISTERS 0 +Index: sljit/sljitConfig.h +=================================================================== +--- sljit/sljitConfig.h (revision 1554) ++++ sljit/sljitConfig.h (working copy) +@@ -96,6 +96,15 @@ + #define SLJIT_EXECUTABLE_ALLOCATOR 1 + #endif + ++/* Force cdecl calling convention even if a better calling ++ convention (e.g. fastcall) is supported by the C compiler. ++ If this option is enabled, C functions without ++ SLJIT_CALL can also be called from JIT code. */ ++#ifndef SLJIT_USE_CDECL_CALLING_CONVENTION ++/* Disabled by default */ ++#define SLJIT_USE_CDECL_CALLING_CONVENTION 0 ++#endif ++ + /* Return with error when an invalid argument is passed. */ + #ifndef SLJIT_ARGUMENT_CHECKS + /* Disabled by default */ +Index: sljit/sljitNativeTILEGX_64.c +=================================================================== +--- sljit/sljitNativeTILEGX_64.c (revision 1554) ++++ sljit/sljitNativeTILEGX_64.c (working copy) +@@ -35,21 +35,21 @@ + #define SIMM_16BIT_MIN (-0x8000) + #define SIMM_17BIT_MAX (0xffff) + #define SIMM_17BIT_MIN (-0x10000) +-#define SIMM_32BIT_MIN (-0x80000000) + #define SIMM_32BIT_MAX (0x7fffffff) +-#define SIMM_48BIT_MIN (0x800000000000L) ++#define SIMM_32BIT_MIN (-0x7fffffff - 1) + #define SIMM_48BIT_MAX (0x7fffffff0000L) ++#define SIMM_48BIT_MIN (-0x800000000000L) + #define IMM16(imm) ((imm) & 0xffff) + + #define UIMM_16BIT_MAX (0xffff) + +-#define TMP_REG1 (SLJIT_NO_REGISTERS + 1) +-#define TMP_REG2 (SLJIT_NO_REGISTERS + 2) +-#define TMP_REG3 (SLJIT_NO_REGISTERS + 3) +-#define ADDR_TMP (SLJIT_NO_REGISTERS + 4) ++#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) ++#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) ++#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4) ++#define ADDR_TMP (SLJIT_NUMBER_OF_REGISTERS + 5) + #define PIC_ADDR_REG TMP_REG2 + +-static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { ++static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = { + 63, 0, 1, 2, 3, 4, 30, 31, 32, 33, 34, 54, 5, 16, 6, 7 + }; + +@@ -58,11 +58,6 @@ + #define TMP_REG2_mapped 16 + #define TMP_REG3_mapped 6 + #define ADDR_TMP_mapped 7 +-#define SLJIT_SAVED_REG1_mapped 30 +-#define SLJIT_SAVED_REG2_mapped 31 +-#define SLJIT_SAVED_REG3_mapped 32 +-#define SLJIT_SAVED_EREG1_mapped 33 +-#define SLJIT_SAVED_EREG2_mapped 34 + + /* Flags are keept in volatile registers. */ + #define EQUAL_FLAG 8 +@@ -399,6 +394,9 @@ + #define SUB(dst, srca, srcb) \ + push_3_buffer(compiler, TILEGX_OPC_SUB, dst, srca, srcb, __LINE__) + ++#define MUL(dst, srca, srcb) \ ++ push_3_buffer(compiler, TILEGX_OPC_MULX, dst, srca, srcb, __LINE__) ++ + #define NOR(dst, srca, srcb) \ + push_3_buffer(compiler, TILEGX_OPC_NOR, dst, srca, srcb, __LINE__) + +@@ -547,8 +545,8 @@ + + const struct Format* match = NULL; + const struct Format *b = NULL; +- unsigned int i = 0; +- for (i; i < sizeof formats / sizeof formats[0]; i++) { ++ unsigned int i; ++ for (i = 0; i < sizeof formats / sizeof formats[0]; i++) { + b = &formats[i]; + if ((b->pipe_mask & compatible_pipes) == b->pipe_mask) { + match = b; +@@ -625,7 +623,6 @@ + + static sljit_si update_buffer(struct sljit_compiler *compiler) + { +- int count; + int i; + int orig_index = inst_buf_index; + struct jit_instr inst0 = inst_buf[0]; +@@ -738,8 +735,10 @@ + + static sljit_si flush_buffer(struct sljit_compiler *compiler) + { +- while (inst_buf_index != 0) +- update_buffer(compiler); ++ while (inst_buf_index != 0) { ++ FAIL_IF(update_buffer(compiler)); ++ } ++ return SLJIT_SUCCESS; + } + + static sljit_si push_4_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int op2, int op3, int line) +@@ -787,6 +786,7 @@ + case TILEGX_OPC_ADD: + case TILEGX_OPC_AND: + case TILEGX_OPC_SUB: ++ case TILEGX_OPC_MULX: + case TILEGX_OPC_OR: + case TILEGX_OPC_XOR: + case TILEGX_OPC_NOR: +@@ -905,7 +905,6 @@ + sljit_sw diff; + sljit_uw target_addr; + sljit_ins *inst; +- sljit_ins saved_inst; + + if (jump->flags & SLJIT_REWRITABLE_JUMP) + return code_ptr; +@@ -1009,7 +1008,7 @@ + struct sljit_const *const_; + + CHECK_ERROR_PTR(); +- check_sljit_generate_code(compiler); ++ CHECK_PTR(check_sljit_generate_code(compiler)); + reverse_buf(compiler); + + code = (sljit_ins *)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins)); +@@ -1178,13 +1177,13 @@ + sljit_si fscratches, sljit_si fsaveds, sljit_si local_size) + { + sljit_ins base; +- sljit_ins bundle = 0; +- ++ sljit_si i, tmp; ++ + CHECK_ERROR(); +- check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); ++ CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size)); + set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); + +- local_size += (saveds + 1) * sizeof(sljit_sw); ++ local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1); + local_size = (local_size + 7) & ~7; + compiler->local_size = local_size; + +@@ -1200,46 +1199,41 @@ + local_size = 0; + } + ++ /* Save the return address. */ + FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 8)); + FAIL_IF(ST_ADD(ADDR_TMP_mapped, RA, -8)); + +- if (saveds >= 1) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_REG1_mapped, -8)); ++ /* Save the S registers. */ ++ tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG; ++ for (i = SLJIT_S0; i >= tmp; i--) { ++ FAIL_IF(ST_ADD(ADDR_TMP_mapped, reg_map[i], -8)); ++ } + +- if (saveds >= 2) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_REG2_mapped, -8)); ++ /* Save the R registers that need to be reserved. */ ++ for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { ++ FAIL_IF(ST_ADD(ADDR_TMP_mapped, reg_map[i], -8)); ++ } + +- if (saveds >= 3) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_REG3_mapped, -8)); ++ /* Move the arguments to S registers. */ ++ for (i = 0; i < args; i++) { ++ FAIL_IF(ADD(reg_map[SLJIT_S0 - i], i, ZERO)); ++ } + +- if (saveds >= 4) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_EREG1_mapped, -8)); +- +- if (saveds >= 5) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_EREG2_mapped, -8)); +- +- if (args >= 1) +- FAIL_IF(ADD(SLJIT_SAVED_REG1_mapped, 0, ZERO)); +- +- if (args >= 2) +- FAIL_IF(ADD(SLJIT_SAVED_REG2_mapped, 1, ZERO)); +- +- if (args >= 3) +- FAIL_IF(ADD(SLJIT_SAVED_REG3_mapped, 2, ZERO)); +- + return SLJIT_SUCCESS; + } + +-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler, + sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds, + sljit_si fscratches, sljit_si fsaveds, sljit_si local_size) + { +- CHECK_ERROR_VOID(); +- check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); ++ CHECK_ERROR(); ++ CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size)); + set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); + +- local_size += (saveds + 1) * sizeof(sljit_sw); ++ local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1); + compiler->local_size = (local_size + 7) & ~7; ++ ++ return SLJIT_SUCCESS; + } + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) +@@ -1246,10 +1240,11 @@ + { + sljit_si local_size; + sljit_ins base; +- int addr_initialized = 0; ++ sljit_si i, tmp; ++ sljit_si saveds; + + CHECK_ERROR(); +- check_sljit_emit_return(compiler, op, src, srcw); ++ CHECK(check_sljit_emit_return(compiler, op, src, srcw)); + + FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); + +@@ -1263,52 +1258,22 @@ + local_size = 0; + } + ++ /* Restore the return address. */ + FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 8)); +- FAIL_IF(LD(RA, ADDR_TMP_mapped)); ++ FAIL_IF(LD_ADD(RA, ADDR_TMP_mapped, -8)); + +- if (compiler->saveds >= 5) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 48)); +- addr_initialized = 1; +- +- FAIL_IF(LD_ADD(SLJIT_SAVED_EREG2_mapped, ADDR_TMP_mapped, 8)); ++ /* Restore the S registers. */ ++ saveds = compiler->saveds; ++ tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG; ++ for (i = SLJIT_S0; i >= tmp; i--) { ++ FAIL_IF(LD_ADD(reg_map[i], ADDR_TMP_mapped, -8)); + } + +- if (compiler->saveds >= 4) { +- if (addr_initialized == 0) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 40)); +- addr_initialized = 1; +- } +- +- FAIL_IF(LD_ADD(SLJIT_SAVED_EREG1_mapped, ADDR_TMP_mapped, 8)); ++ /* Restore the R registers that need to be reserved. */ ++ for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { ++ FAIL_IF(LD_ADD(reg_map[i], ADDR_TMP_mapped, -8)); + } + +- if (compiler->saveds >= 3) { +- if (addr_initialized == 0) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 32)); +- addr_initialized = 1; +- } +- +- FAIL_IF(LD_ADD(SLJIT_SAVED_REG3_mapped, ADDR_TMP_mapped, 8)); +- } +- +- if (compiler->saveds >= 2) { +- if (addr_initialized == 0) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 24)); +- addr_initialized = 1; +- } +- +- FAIL_IF(LD_ADD(SLJIT_SAVED_REG2_mapped, ADDR_TMP_mapped, 8)); +- } +- +- if (compiler->saveds >= 1) { +- if (addr_initialized == 0) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 16)); +- /* addr_initialized = 1; no need to initialize as it's the last one. */ +- } +- +- FAIL_IF(LD_ADD(SLJIT_SAVED_REG1_mapped, ADDR_TMP_mapped, 8)); +- } +- + if (compiler->local_size <= SIMM_16BIT_MAX) + FAIL_IF(ADDLI(SLJIT_LOCALS_REG_mapped, SLJIT_LOCALS_REG_mapped, compiler->local_size)); + else +@@ -1585,7 +1550,7 @@ + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw) + { + CHECK_ERROR(); +- check_sljit_emit_fast_enter(compiler, dst, dstw); ++ CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); + ADJUST_LOCAL_OFFSET(dst, dstw); + + /* For UNUSED dst. Uncommon, but possible. */ +@@ -1602,7 +1567,7 @@ + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw) + { + CHECK_ERROR(); +- check_sljit_emit_fast_return(compiler, src, srcw); ++ CHECK(check_sljit_emit_fast_return(compiler, src, srcw)); + ADJUST_LOCAL_OFFSET(src, srcw); + + if (FAST_IS_REG(src)) +@@ -1636,9 +1601,11 @@ + if (op == SLJIT_MOV_SI) + return BFEXTS(reg_map[dst], reg_map[src2], 0, 31); + +- return BFEXTU(reg_map[dst], reg_map[src2], 0, 31); +- } else if (dst != src2) +- SLJIT_ASSERT_STOP(); ++ return BFEXTU(reg_map[dst], reg_map[src2], 0, 31); ++ } else if (dst != src2) { ++ SLJIT_ASSERT(src2 == 0); ++ return ADD(reg_map[dst], reg_map[src2], ZERO); ++ } + + return SLJIT_SUCCESS; + +@@ -1650,8 +1617,10 @@ + return BFEXTS(reg_map[dst], reg_map[src2], 0, 7); + + return BFEXTU(reg_map[dst], reg_map[src2], 0, 7); +- } else if (dst != src2) +- SLJIT_ASSERT_STOP(); ++ } else if (dst != src2) { ++ SLJIT_ASSERT(src2 == 0); ++ return ADD(reg_map[dst], reg_map[src2], ZERO); ++ } + + return SLJIT_SUCCESS; + +@@ -1663,8 +1632,10 @@ + return BFEXTS(reg_map[dst], reg_map[src2], 0, 15); + + return BFEXTU(reg_map[dst], reg_map[src2], 0, 15); +- } else if (dst != src2) +- SLJIT_ASSERT_STOP(); ++ } else if (dst != src2) { ++ SLJIT_ASSERT(src2 == 0); ++ return ADD(reg_map[dst], reg_map[src2], ZERO); ++ } + + return SLJIT_SUCCESS; + +@@ -1811,7 +1782,6 @@ + else { + /* Rare ocasion. */ + FAIL_IF(ADD(TMP_EREG2, reg_map[src1], ZERO)); +- + overflow_ra = TMP_EREG2; + } + } +@@ -1903,6 +1873,17 @@ + + return SLJIT_SUCCESS; + ++ case SLJIT_MUL: ++ if (flags & SRC2_IMM) { ++ FAIL_IF(load_immediate(compiler, TMP_REG2_mapped, src2)); ++ src2 = TMP_REG2; ++ flags &= ~SRC2_IMM; ++ } ++ ++ FAIL_IF(MUL(reg_map[dst], reg_map[src1], reg_map[src2])); ++ ++ return SLJIT_SUCCESS; ++ + #define EMIT_LOGICAL(op_imm, op_norm) \ + if (flags & SRC2_IMM) { \ + FAIL_IF(load_immediate(compiler, ADDR_TMP_mapped, src2)); \ +@@ -1950,8 +1931,8 @@ + } else { \ + if (op & SLJIT_SET_E) \ + FAIL_IF(push_3_buffer( \ +- compiler, op_imm, reg_map[dst], reg_map[src1], \ +- src2 & 0x3F, __LINE__)); \ ++ compiler, op_norm, EQUAL_FLAG, reg_map[src1], \ ++ reg_map[src2], __LINE__)); \ + if (CHECK_FLAGS(SLJIT_SET_E)) \ + FAIL_IF(push_3_buffer( \ + compiler, op_norm, reg_map[dst], reg_map[src1], \ +@@ -2105,9 +2086,10 @@ + { + sljit_si sugg_dst_ar, dst_ar; + sljit_si flags = GET_ALL_FLAGS(op); ++ sljit_si mem_type = (op & SLJIT_INT_OP) ? (INT_DATA | SIGNED_DATA) : WORD_DATA; + + CHECK_ERROR(); +- check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type); ++ CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type)); + ADJUST_LOCAL_OFFSET(dst, dstw); + + if (dst == SLJIT_UNUSED) +@@ -2114,6 +2096,8 @@ + return SLJIT_SUCCESS; + + op = GET_OPCODE(op); ++ if (op == SLJIT_MOV_SI || op == SLJIT_MOV_UI) ++ mem_type = INT_DATA | SIGNED_DATA; + sugg_dst_ar = reg_map[(op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2]; + + compiler->cache_arg = 0; +@@ -2120,51 +2104,43 @@ + compiler->cache_argw = 0; + if (op >= SLJIT_ADD && (src & SLJIT_MEM)) { + ADJUST_LOCAL_OFFSET(src, srcw); +- FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1_mapped, src, srcw, dst, dstw)); ++ FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, TMP_REG1_mapped, src, srcw, dst, dstw)); + src = TMP_REG1; + srcw = 0; + } + +- switch (type) { +- case SLJIT_C_EQUAL: +- case SLJIT_C_NOT_EQUAL: ++ switch (type & 0xff) { ++ case SLJIT_EQUAL: ++ case SLJIT_NOT_EQUAL: + FAIL_IF(CMPLTUI(sugg_dst_ar, EQUAL_FLAG, 1)); + dst_ar = sugg_dst_ar; + break; +- case SLJIT_C_LESS: +- case SLJIT_C_GREATER_EQUAL: +- case SLJIT_C_FLOAT_LESS: +- case SLJIT_C_FLOAT_GREATER_EQUAL: ++ case SLJIT_LESS: ++ case SLJIT_GREATER_EQUAL: + dst_ar = ULESS_FLAG; + break; +- case SLJIT_C_GREATER: +- case SLJIT_C_LESS_EQUAL: +- case SLJIT_C_FLOAT_GREATER: +- case SLJIT_C_FLOAT_LESS_EQUAL: ++ case SLJIT_GREATER: ++ case SLJIT_LESS_EQUAL: + dst_ar = UGREATER_FLAG; + break; +- case SLJIT_C_SIG_LESS: +- case SLJIT_C_SIG_GREATER_EQUAL: ++ case SLJIT_SIG_LESS: ++ case SLJIT_SIG_GREATER_EQUAL: + dst_ar = LESS_FLAG; + break; +- case SLJIT_C_SIG_GREATER: +- case SLJIT_C_SIG_LESS_EQUAL: ++ case SLJIT_SIG_GREATER: ++ case SLJIT_SIG_LESS_EQUAL: + dst_ar = GREATER_FLAG; + break; +- case SLJIT_C_OVERFLOW: +- case SLJIT_C_NOT_OVERFLOW: ++ case SLJIT_OVERFLOW: ++ case SLJIT_NOT_OVERFLOW: + dst_ar = OVERFLOW_FLAG; + break; +- case SLJIT_C_MUL_OVERFLOW: +- case SLJIT_C_MUL_NOT_OVERFLOW: ++ case SLJIT_MUL_OVERFLOW: ++ case SLJIT_MUL_NOT_OVERFLOW: + FAIL_IF(CMPLTUI(sugg_dst_ar, OVERFLOW_FLAG, 1)); + dst_ar = sugg_dst_ar; + type ^= 0x1; /* Flip type bit for the XORI below. */ + break; +- case SLJIT_C_FLOAT_EQUAL: +- case SLJIT_C_FLOAT_NOT_EQUAL: +- dst_ar = EQUAL_FLAG; +- break; + + default: + SLJIT_ASSERT_STOP(); +@@ -2180,11 +2156,11 @@ + if (op >= SLJIT_ADD) { + if (TMP_REG2_mapped != dst_ar) + FAIL_IF(ADD(TMP_REG2_mapped, dst_ar, ZERO)); +- return emit_op(compiler, op | flags, CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0); ++ return emit_op(compiler, op | flags, mem_type | CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0); + } + + if (dst & SLJIT_MEM) +- return emit_op_mem(compiler, WORD_DATA, dst_ar, dst, dstw); ++ return emit_op_mem(compiler, mem_type, dst_ar, dst, dstw); + + if (sugg_dst_ar != dst_ar) + return ADD(sugg_dst_ar, dst_ar, ZERO); +@@ -2194,7 +2170,7 @@ + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) { + CHECK_ERROR(); +- check_sljit_emit_op0(compiler, op); ++ CHECK(check_sljit_emit_op0(compiler, op)); + + op = GET_OPCODE(op); + switch (op) { +@@ -2204,10 +2180,10 @@ + case SLJIT_BREAKPOINT: + return PI(BPT); + +- case SLJIT_UMUL: +- case SLJIT_SMUL: +- case SLJIT_UDIV: +- case SLJIT_SDIV: ++ case SLJIT_LUMUL: ++ case SLJIT_LSMUL: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: + SLJIT_ASSERT_STOP(); + } + +@@ -2217,7 +2193,7 @@ + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src, sljit_sw srcw) + { + CHECK_ERROR(); +- check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw); ++ CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw)); + ADJUST_LOCAL_OFFSET(dst, dstw); + ADJUST_LOCAL_OFFSET(src, srcw); + +@@ -2273,7 +2249,7 @@ + return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw); + + case SLJIT_CLZ: +- return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw); ++ return emit_op(compiler, op, (op & SLJIT_INT_OP) ? INT_DATA : WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + } + + return SLJIT_SUCCESS; +@@ -2282,7 +2258,7 @@ + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src1, sljit_sw src1w, sljit_si src2, sljit_sw src2w) + { + CHECK_ERROR(); +- check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w); ++ CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); + ADJUST_LOCAL_OFFSET(dst, dstw); + ADJUST_LOCAL_OFFSET(src1, src1w); + ADJUST_LOCAL_OFFSET(src2, src2w); +@@ -2325,7 +2301,7 @@ + flush_buffer(compiler); + + CHECK_ERROR_PTR(); +- check_sljit_emit_label(compiler); ++ CHECK_PTR(check_sljit_emit_label(compiler)); + + if (compiler->last_label && compiler->last_label->size == compiler->size) + return compiler->last_label; +@@ -2344,7 +2320,7 @@ + flush_buffer(compiler); + + CHECK_ERROR(); +- check_sljit_emit_ijump(compiler, type, src, srcw); ++ CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); + ADJUST_LOCAL_OFFSET(src, srcw); + + if (FAST_IS_REG(src)) { +@@ -2404,8 +2380,10 @@ + + return SLJIT_SUCCESS; + +- } else if (src & SLJIT_MEM) ++ } else if (src & SLJIT_MEM) { + FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_REG2, 0, TMP_REG1, 0, src, srcw)); ++ flush_buffer(compiler); ++ } + + FAIL_IF(JR_SOLO(reg_map[src_r])); + +@@ -2432,7 +2410,7 @@ + flush_buffer(compiler); + + CHECK_ERROR_PTR(); +- check_sljit_emit_jump(compiler, type); ++ CHECK_PTR(check_sljit_emit_jump(compiler, type)); + + jump = (struct sljit_jump *)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); +@@ -2440,48 +2418,42 @@ + type &= 0xff; + + switch (type) { +- case SLJIT_C_EQUAL: +- case SLJIT_C_FLOAT_NOT_EQUAL: ++ case SLJIT_EQUAL: + BR_NZ(EQUAL_FLAG); + break; +- case SLJIT_C_NOT_EQUAL: +- case SLJIT_C_FLOAT_EQUAL: ++ case SLJIT_NOT_EQUAL: + BR_Z(EQUAL_FLAG); + break; +- case SLJIT_C_LESS: +- case SLJIT_C_FLOAT_LESS: ++ case SLJIT_LESS: + BR_Z(ULESS_FLAG); + break; +- case SLJIT_C_GREATER_EQUAL: +- case SLJIT_C_FLOAT_GREATER_EQUAL: ++ case SLJIT_GREATER_EQUAL: + BR_NZ(ULESS_FLAG); + break; +- case SLJIT_C_GREATER: +- case SLJIT_C_FLOAT_GREATER: ++ case SLJIT_GREATER: + BR_Z(UGREATER_FLAG); + break; +- case SLJIT_C_LESS_EQUAL: +- case SLJIT_C_FLOAT_LESS_EQUAL: ++ case SLJIT_LESS_EQUAL: + BR_NZ(UGREATER_FLAG); + break; +- case SLJIT_C_SIG_LESS: ++ case SLJIT_SIG_LESS: + BR_Z(LESS_FLAG); + break; +- case SLJIT_C_SIG_GREATER_EQUAL: ++ case SLJIT_SIG_GREATER_EQUAL: + BR_NZ(LESS_FLAG); + break; +- case SLJIT_C_SIG_GREATER: ++ case SLJIT_SIG_GREATER: + BR_Z(GREATER_FLAG); + break; +- case SLJIT_C_SIG_LESS_EQUAL: ++ case SLJIT_SIG_LESS_EQUAL: + BR_NZ(GREATER_FLAG); + break; +- case SLJIT_C_OVERFLOW: +- case SLJIT_C_MUL_OVERFLOW: ++ case SLJIT_OVERFLOW: ++ case SLJIT_MUL_OVERFLOW: + BR_Z(OVERFLOW_FLAG); + break; +- case SLJIT_C_NOT_OVERFLOW: +- case SLJIT_C_MUL_NOT_OVERFLOW: ++ case SLJIT_NOT_OVERFLOW: ++ case SLJIT_MUL_NOT_OVERFLOW: + BR_NZ(OVERFLOW_FLAG); + break; + default: +@@ -2536,7 +2508,7 @@ + flush_buffer(compiler); + + CHECK_ERROR_PTR(); +- check_sljit_emit_const(compiler, dst, dstw, init_value); ++ CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value)); + ADJUST_LOCAL_OFFSET(dst, dstw); + + const_ = (struct sljit_const *)ensure_abuf(compiler, sizeof(struct sljit_const)); +@@ -2572,3 +2544,18 @@ + inst[3] = (inst[3] & ~(0xFFFFL << 43)) | ((new_constant & 0xFFFFL) << 43); + SLJIT_CACHE_FLUSH(inst, inst + 4); + } ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg) ++{ ++ CHECK_REG_INDEX(check_sljit_get_register_index(reg)); ++ return reg_map[reg]; ++} ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, ++ void *instruction, sljit_si size) ++{ ++ CHECK_ERROR(); ++ CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); ++ return SLJIT_ERR_UNSUPPORTED; ++} ++ +Index: pcregrep.c +=================================================================== +--- pcregrep.c (revision 1554) ++++ pcregrep.c (working copy) +@@ -1692,9 +1692,13 @@ + + if (filenames == FN_NOMATCH_ONLY) return 1; + ++ /* If all we want is a yes/no answer, stop now. */ ++ ++ if (quiet) return 0; ++ + /* Just count if just counting is wanted. */ + +- if (count_only) count++; ++ else if (count_only) count++; + + /* When handling a binary file and binary-files==binary, the "binary" + variable will be set true (it's false in all other cases). In this +@@ -1715,10 +1719,6 @@ + return 0; + } + +- /* Likewise, if all we want is a yes/no answer. */ +- +- else if (quiet) return 0; +- + /* The --only-matching option prints just the substring that matched, + and/or one or more captured portions of it, as long as these strings are + not empty. The --file-offsets and --line-offsets options output offsets for +@@ -2089,7 +2089,7 @@ + + /* Print the match count if wanted */ + +-if (count_only) ++if (count_only && !quiet) + { + if (count > 0 || !omit_zero_count) + { +Index: pcre_study.c +=================================================================== +--- pcre_study.c (revision 1554) ++++ pcre_study.c (working copy) +@@ -71,6 +71,7 @@ + startcode pointer to start of the whole pattern's code + options the compiling options + recurses chain of recurse_check to catch mutual recursion ++ countptr pointer to call count (to catch over complexity) + + Returns: the minimum length + -1 if \C in UTF-8 mode or (*ACCEPT) was encountered +@@ -80,7 +81,8 @@ + + static int + find_minlength(const REAL_PCRE *re, const pcre_uchar *code, +- const pcre_uchar *startcode, int options, recurse_check *recurses) ++ const pcre_uchar *startcode, int options, recurse_check *recurses, ++ int *countptr) + { + int length = -1; + /* PCRE_UTF16 has the same value as PCRE_UTF8. */ +@@ -90,6 +92,8 @@ + register int branchlength = 0; + register pcre_uchar *cc = (pcre_uchar *)code + 1 + LINK_SIZE; + ++if ((*countptr)++ > 1000) return -1; /* too complex */ ++ + if (*code == OP_CBRA || *code == OP_SCBRA || + *code == OP_CBRAPOS || *code == OP_SCBRAPOS) cc += IMM2_SIZE; + +@@ -131,7 +135,7 @@ + case OP_SBRAPOS: + case OP_ONCE: + case OP_ONCE_NC: +- d = find_minlength(re, cc, startcode, options, recurses); ++ d = find_minlength(re, cc, startcode, options, recurses, countptr); + if (d < 0) return d; + branchlength += d; + do cc += GET(cc, 1); while (*cc == OP_ALT); +@@ -415,7 +419,8 @@ + int dd; + this_recurse.prev = recurses; + this_recurse.group = cs; +- dd = find_minlength(re, cs, startcode, options, &this_recurse); ++ dd = find_minlength(re, cs, startcode, options, &this_recurse, ++ countptr); + if (dd < d) d = dd; + } + } +@@ -451,7 +456,8 @@ + { + this_recurse.prev = recurses; + this_recurse.group = cs; +- d = find_minlength(re, cs, startcode, options, &this_recurse); ++ d = find_minlength(re, cs, startcode, options, &this_recurse, ++ countptr); + } + } + } +@@ -514,7 +520,7 @@ + this_recurse.prev = recurses; + this_recurse.group = cs; + branchlength += find_minlength(re, cs, startcode, options, +- &this_recurse); ++ &this_recurse, countptr); + } + } + cc += 1 + LINK_SIZE; +@@ -1453,6 +1459,7 @@ + #endif + { + int min; ++int count = 0; + BOOL bits_set = FALSE; + pcre_uint8 start_bits[32]; + PUBL(extra) *extra = NULL; +@@ -1539,7 +1546,7 @@ + + /* Find the minimum length of subject string. */ + +-switch(min = find_minlength(re, code, code, re->options, NULL)) ++switch(min = find_minlength(re, code, code, re->options, NULL, &count)) + { + case -2: *errorptr = "internal error: missing capturing bracket"; return NULL; + case -3: *errorptr = "internal error: opcode not recognized"; return NULL; +Index: pcre_internal.h +=================================================================== +--- pcre_internal.h (revision 1554) ++++ pcre_internal.h (working copy) +@@ -984,7 +984,7 @@ + #ifndef EBCDIC + + #define HSPACE_LIST \ +- CHAR_HT, CHAR_SPACE, 0xa0, \ ++ CHAR_HT, CHAR_SPACE, CHAR_NBSP, \ + 0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, \ + 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202f, 0x205f, 0x3000, \ + NOTACHAR +@@ -1010,7 +1010,7 @@ + #define HSPACE_BYTE_CASES \ + case CHAR_HT: \ + case CHAR_SPACE: \ +- case 0xa0 /* NBSP */ ++ case CHAR_NBSP + + #define HSPACE_CASES \ + HSPACE_BYTE_CASES: \ +@@ -1037,11 +1037,12 @@ + /* ------ EBCDIC environments ------ */ + + #else +-#define HSPACE_LIST CHAR_HT, CHAR_SPACE ++#define HSPACE_LIST CHAR_HT, CHAR_SPACE, CHAR_NBSP, NOTACHAR + + #define HSPACE_BYTE_CASES \ + case CHAR_HT: \ +- case CHAR_SPACE ++ case CHAR_SPACE: \ ++ case CHAR_NBSP + + #define HSPACE_CASES HSPACE_BYTE_CASES + +@@ -1215,6 +1216,7 @@ + + #define CHAR_ESC '\047' + #define CHAR_DEL '\007' ++#define CHAR_NBSP '\x41' + #define STR_ESC "\047" + #define STR_DEL "\007" + +@@ -1229,6 +1231,7 @@ + #define CHAR_NEL ((unsigned char)'\x85') + #define CHAR_ESC '\033' + #define CHAR_DEL '\177' ++#define CHAR_NBSP ((unsigned char)'\xa0') + + #define STR_LF "\n" + #define STR_NL STR_LF +@@ -1606,6 +1609,7 @@ + #define CHAR_VERTICAL_LINE '\174' + #define CHAR_RIGHT_CURLY_BRACKET '\175' + #define CHAR_TILDE '\176' ++#define CHAR_NBSP ((unsigned char)'\xa0') + + #define STR_HT "\011" + #define STR_VT "\013" +@@ -1762,6 +1766,10 @@ + + /* Escape items that are just an encoding of a particular data value. */ + ++#ifndef ESC_a ++#define ESC_a CHAR_BEL ++#endif ++ + #ifndef ESC_e + #define ESC_e CHAR_ESC + #endif +@@ -2446,6 +2454,7 @@ + BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ + BOOL check_lookbehind; /* Lookbehinds need later checking */ + BOOL dupnames; /* Duplicate names exist */ ++ BOOL dupgroups; /* Duplicate groups exist: (?| found */ + BOOL iscondassert; /* Next assert is a condition */ + int nltype; /* Newline type */ + int nllen; /* Newline string length */ +Index: pcre_exec.c +=================================================================== +--- pcre_exec.c (revision 1554) ++++ pcre_exec.c (working copy) +@@ -6685,7 +6685,8 @@ + register int *iend = iptr - re->top_bracket; + if (iend < md->offset_vector + 2) iend = md->offset_vector + 2; + while (--iptr >= iend) *iptr = -1; +- md->offset_vector[0] = md->offset_vector[1] = -1; ++ if (offsetcount > 0) md->offset_vector[0] = -1; ++ if (offsetcount > 1) md->offset_vector[1] = -1; + } + + /* Set up the first character to match, if available. The first_char value is +Index: pcre_jit_test.c +=================================================================== +--- pcre_jit_test.c (revision 1554) ++++ pcre_jit_test.c (working copy) +@@ -182,6 +182,7 @@ + { CMUAP, 0, "\xf0\x90\x90\x80{2}", "\xf0\x90\x90\x80#\xf0\x90\x90\xa8\xf0\x90\x90\x80" }, + { CMUAP, 0, "\xf0\x90\x90\xa8{2}", "\xf0\x90\x90\x80#\xf0\x90\x90\xa8\xf0\x90\x90\x80" }, + { CMUAP, 0, "\xe1\xbd\xb8\xe1\xbf\xb8", "\xe1\xbf\xb8\xe1\xbd\xb8" }, ++ { MA, 0, "[3-57-9]", "5" }, + + /* Assertions. */ + { MUA, 0, "\\b[^A]", "A_B#" }, +Index: configure.ac +=================================================================== +--- configure.ac (revision 1554) ++++ configure.ac (working copy) +@@ -9,9 +9,9 @@ + dnl be defined as -RC2, for example. For real releases, it should be empty. + + m4_define(pcre_major, [8]) +-m4_define(pcre_minor, [37]) +-m4_define(pcre_prerelease, []) +-m4_define(pcre_date, [2015-04-28]) ++m4_define(pcre_minor, [38]) ++m4_define(pcre_prerelease, [-RC1]) ++m4_define(pcre_date, [2015-05-03]) + + # NOTE: The CMakeLists.txt file searches for the above variables in the first + # 50 lines of this file. Please update that if the variables above are moved. +Index: doc/pcrepattern.3 +=================================================================== +--- doc/pcrepattern.3 (revision 1554) ++++ doc/pcrepattern.3 (working copy) +@@ -1,4 +1,4 @@ +-.TH PCREPATTERN 3 "08 January 2014" "PCRE 8.35" ++.TH PCREPATTERN 3 "14 June 2015" "PCRE 8.38" + .SH NAME + PCRE - Perl-compatible regular expressions + .SH "PCRE REGULAR EXPRESSION DETAILS" +@@ -308,7 +308,8 @@ + in patterns in a visible manner. There is no restriction on the appearance of + non-printing characters, apart from the binary zero that terminates a pattern, + but when a pattern is being prepared by text editing, it is often easier to use +-one of the following escape sequences than the binary character it represents: ++one of the following escape sequences than the binary character it represents. ++In an ASCII or Unicode environment, these escapes are as follows: + .sp + \ea alarm, that is, the BEL character (hex 07) + \ecx "control-x", where x is any ASCII character +@@ -330,19 +331,31 @@ + but \ec{ becomes hex 3B ({ is 7B), and \ec; becomes hex 7B (; is 3B). If the + data item (byte or 16-bit value) following \ec has a value greater than 127, a + compile-time error occurs. This locks out non-ASCII characters in all modes. ++.P ++When PCRE is compiled in EBCDIC mode, \ea, \ee, \ef, \en, \er, and \et ++generate the appropriate EBCDIC code values. The \ec escape is processed ++as specified for Perl in the \fBperlebcdic\fP document. The only characters ++that are allowed after \ec are A-Z, a-z, or one of @, [, \e, ], ^, _, or ?. Any ++other character provokes a compile-time error. The sequence \e@ encodes ++character code 0; the letters (in either case) encode characters 1-26 (hex 01 ++to hex 1A); [, \e, ], ^, and _ encode characters 27-31 (hex 1B to hex 1F), and ++\e? becomes either 255 (hex FF) or 95 (hex 5F). + .P +-The \ec facility was designed for use with ASCII characters, but with the +-extension to Unicode it is even less useful than it once was. It is, however, +-recognized when PCRE is compiled in EBCDIC mode, where data items are always +-bytes. In this mode, all values are valid after \ec. If the next character is a +-lower case letter, it is converted to upper case. Then the 0xc0 bits of the +-byte are inverted. Thus \ecA becomes hex 01, as in ASCII (A is C1), but because +-the EBCDIC letters are disjoint, \ecZ becomes hex 29 (Z is E9), and other +-characters also generate different values. ++Thus, apart from \e?, these escapes generate the same character code values as ++they do in an ASCII environment, though the meanings of the values mostly ++differ. For example, \eG always generates code value 7, which is BEL in ASCII ++but DEL in EBCDIC. + .P ++The sequence \e? generates DEL (127, hex 7F) in an ASCII environment, but ++because 127 is not a control character in EBCDIC, Perl makes it generate the ++APC character. Unfortunately, there are several variants of EBCDIC. In most of ++them the APC character has the value 255 (hex FF), but in the one Perl calls ++POSIX-BC its value is 95 (hex 5F). If certain other characters have POSIX-BC ++values, PCRE makes \e? generate 95; otherwise it generates 255. ++.P + After \e0 up to two further octal digits are read. If there are fewer than two +-digits, just those that are present are used. Thus the sequence \e0\ex\e07 +-specifies two binary zeros followed by a BEL character (code value 7). Make ++digits, just those that are present are used. Thus the sequence \e0\ex\e015 ++specifies two binary zeros followed by a CR character (code value 13). Make + sure you supply two digits after the initial zero if the pattern character that + follows is itself an octal digit. + .P +@@ -3283,6 +3296,6 @@ + .rs + .sp + .nf +-Last updated: 08 January 2014 +-Copyright (c) 1997-2014 University of Cambridge. ++Last updated: 14 June 2015 ++Copyright (c) 1997-2015 University of Cambridge. + .fi +Index: testdata/testoutput11-32 +=================================================================== +--- testdata/testoutput11-32 (revision 1554) ++++ testdata/testoutput11-32 (working copy) +@@ -231,7 +231,7 @@ + ------------------------------------------------------------------ + + /(?Pa)...(?P=a)bbb(?P>a)d/BM +-Memory allocation (code space): 125 ++Memory allocation (code space): 157 + ------------------------------------------------------------------ + 0 24 Bra + 2 5 CBra 1 +@@ -748,4 +748,21 @@ + 22 End + ------------------------------------------------------------------ + ++/.((?2)(?R)\1)()/B ++------------------------------------------------------------------ ++ 0 23 Bra ++ 2 Any ++ 3 13 Once ++ 5 9 CBra 1 ++ 8 18 Recurse ++ 10 0 Recurse ++ 12 \1 ++ 14 9 Ket ++ 16 13 Ket ++ 18 3 CBra 2 ++ 21 3 Ket ++ 23 23 Ket ++ 25 End ++------------------------------------------------------------------ ++ + /-- End of testinput11 --/ +Index: testdata/testinputEBC +=================================================================== +--- testdata/testinputEBC (revision 1554) ++++ testdata/testinputEBC (working copy) +@@ -29,13 +29,16 @@ + + /^A\ˆ/ + A B ++ A\x41B + + /-- Test \H --/ + + /^A\È/ + AB ++ A\x42B + ** Fail + A B ++ A\x41B + + /-- Test \R --/ + +Index: testdata/testoutput1 +=================================================================== +--- testdata/testoutput1 (revision 1554) ++++ testdata/testoutput1 (working copy) +@@ -9429,4 +9429,9 @@ + 0: aaaaaaaaa + 1: a + ++"(?|(\k'Pm')|(?'Pm'))" ++ abcd ++ 0: ++ 1: ++ + /-- End of testinput1 --/ +Index: testdata/testoutput2 +=================================================================== +--- testdata/testoutput2 (revision 1554) ++++ testdata/testoutput2 (working copy) +@@ -5614,9 +5614,9 @@ + 123456\P + No match + +-//KF>/dev/null +-Compiled pattern written to /dev/null +-Study data written to /dev/null ++//KF>testsavedregex ++Compiled pattern written to testsavedregex ++Study data written to testsavedregex + + /abc/IS>testsavedregex + Capturing subpattern count = 0 +@@ -9135,10 +9135,10 @@ + Failed: subpattern name expected at offset 3 + + /\k/ +-Failed: \k is not followed by a braced, angle-bracketed, or quoted name at offset 2 ++Failed: \k is not followed by a braced, angle-bracketed, or quoted name at offset 1 + + /\kabc/ +-Failed: \k is not followed by a braced, angle-bracketed, or quoted name at offset 5 ++Failed: \k is not followed by a braced, angle-bracketed, or quoted name at offset 1 + + /(?P=)/ + Failed: subpattern name expected at offset 4 +@@ -9186,7 +9186,7 @@ + Failed: unknown POSIX class name at offset 3 + + /(^(a|b\g<-1'c))/ +-Failed: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number at offset 15 ++Failed: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number at offset 8 + + /^(?+1)(?x|y){0}z/ + xzxx +@@ -14098,10 +14098,10 @@ + Failed: group name must start with a non-digit at offset 4 + + /\g'3gh'/ +-Failed: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number at offset 7 ++Failed: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number at offset 2 + + /\g<5fg>/ +-Failed: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number at offset 7 ++Failed: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number at offset 2 + + /(?(<4gh>)abc)/ + Failed: group name must start with a non-digit at offset 4 +@@ -14423,4 +14423,146 @@ + + /((?2){73}(?2))((?1))/ + ++/.((?2)(?R)\1)()/BZ ++------------------------------------------------------------------ ++ Bra ++ Any ++ Once ++ CBra 1 ++ Recurse ++ Recurse ++ \1 ++ Ket ++ Ket ++ CBra 2 ++ Ket ++ Ket ++ End ++------------------------------------------------------------------ ++ ++/(?1)()((((((\1++))\x85)+)|))/ ++ ++/(\9*+(?2);\3++()2|)++{/ ++Failed: reference to non-existent subpattern at offset 22 ++ ++/\V\x85\9*+((?2)\3++()2)*:2/ ++Failed: reference to non-existent subpattern at offset 26 ++ ++/(((?(R)){0,2}) (?''((?'R')((?'R')))))/J ++ ++/(((?(X)){0,2}) (?''((?'X')((?'X')))))/J ++ ++/(((?(R)){0,2}) (?''((?'X')((?'R')))))/ ++ ++"(?J)(?'d'(?'d'\g{d}))" ++ ++".*?\h.+.\.+\R*?\xd(?i)(?=!(?=b`b`b`\`b\xa9b!)`\a`bbbbbbbbbbbbb`bbbbbbbbbbbb*R\x85bbbbbbb\C?{((?2)(?))(( ++\H){8(?<=(?1){29}\xa8bbbb\x16\xd\xc6^($(?1)/ ++ + /-- End of testinput2 --/ +Index: testdata/testoutput11-16 +=================================================================== +--- testdata/testoutput11-16 (revision 1554) ++++ testdata/testoutput11-16 (working copy) +@@ -231,7 +231,7 @@ + ------------------------------------------------------------------ + + /(?Pa)...(?P=a)bbb(?P>a)d/BM +-Memory allocation (code space): 61 ++Memory allocation (code space): 77 + ------------------------------------------------------------------ + 0 24 Bra + 2 5 CBra 1 +@@ -748,4 +748,21 @@ + 22 End + ------------------------------------------------------------------ + ++/.((?2)(?R)\1)()/B ++------------------------------------------------------------------ ++ 0 23 Bra ++ 2 Any ++ 3 13 Once ++ 5 9 CBra 1 ++ 8 18 Recurse ++ 10 0 Recurse ++ 12 \1 ++ 14 9 Ket ++ 16 13 Ket ++ 18 3 CBra 2 ++ 21 3 Ket ++ 23 23 Ket ++ 25 End ++------------------------------------------------------------------ ++ + /-- End of testinput11 --/ +Index: testdata/testoutput6 +=================================================================== +--- testdata/testoutput6 (revision 1554) ++++ testdata/testoutput6 (working copy) +@@ -2469,4 +2469,8 @@ + Ó…\x0aT + No match + ++/[\pS#moq]/ ++ = ++ 0: = ++ + /-- End of testinput6 --/ +Index: testdata/testinput11 +=================================================================== +--- testdata/testinput11 (revision 1554) ++++ testdata/testinput11 (working copy) +@@ -136,4 +136,6 @@ + + /((?+1)(\1))/B + ++/.((?2)(?R)\1)()/B ++ + /-- End of testinput11 --/ +Index: testdata/testinput12 +=================================================================== +--- testdata/testinput12 (revision 1554) ++++ testdata/testinput12 (working copy) +@@ -8,6 +8,8 @@ + + /(?(?C1)(?=a)a)/S!+I + ++/b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*b*/S+I ++ + /abc/S+I>testsavedregex + + testsavedregex + Capturing subpattern count = 0 + No options +@@ -184,4 +193,12 @@ + + /(a(?:a|b|c|d|e)b){8,16}/S++ + ++/(?:|a|){100}x/S++ ++ ++/(x(?1)){4}/S++ ++ ++/(.|.)*?bx/ ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabax ++Error -8 (match limit exceeded) ++ + /-- End of testinput12 --/ +Index: testdata/testoutput11-8 +=================================================================== +--- testdata/testoutput11-8 (revision 1554) ++++ testdata/testoutput11-8 (working copy) +@@ -231,7 +231,7 @@ + ------------------------------------------------------------------ + + /(?Pa)...(?P=a)bbb(?P>a)d/BM +-Memory allocation (code space): 38 ++Memory allocation (code space): 50 + ------------------------------------------------------------------ + 0 30 Bra + 3 7 CBra 1 +@@ -748,4 +748,21 @@ + 34 End + ------------------------------------------------------------------ + ++/.((?2)(?R)\1)()/B ++------------------------------------------------------------------ ++ 0 35 Bra ++ 3 Any ++ 4 20 Once ++ 7 14 CBra 1 ++ 12 27 Recurse ++ 15 0 Recurse ++ 18 \1 ++ 21 14 Ket ++ 24 20 Ket ++ 27 5 CBra 2 ++ 32 5 Ket ++ 35 35 Ket ++ 38 End ++------------------------------------------------------------------ ++ + /-- End of testinput11 --/ +Index: testdata/testoutputEBC +=================================================================== +--- testdata/testoutputEBC (revision 1554) ++++ testdata/testoutputEBC (working copy) +@@ -41,6 +41,8 @@ + /^A\ˆ/ + A B + 0: A\x20 ++ A\x41B ++ 0: AA + + /-- Test \H --/ + +@@ -47,10 +49,14 @@ + /^A\È/ + AB + 0: AB ++ A\x42B ++ 0: AB + ** Fail + No match + A B + No match ++ A\x41B ++No match + + /-- Test \R --/ + +Index: testdata/grepoutput +=================================================================== +--- testdata/grepoutput (revision 1554) ++++ testdata/grepoutput (working copy) +@@ -751,3 +751,7 @@ + 2:3,1 + 2:4,1 + RC=0 ++---------------------------- Test 108 ------------------------------ ++RC=0 ++---------------------------- Test 109 ----------------------------- ++RC=0 +Index: testdata/testinput1 +=================================================================== +--- testdata/testinput1 (revision 1554) ++++ testdata/testinput1 (working copy) +@@ -5730,4 +5730,7 @@ + "(?1)(?#?'){8}(a)" + baaaaaaaaac + ++"(?|(\k'Pm')|(?'Pm'))" ++ abcd ++ + /-- End of testinput1 --/ +Index: testdata/testinput2 +=================================================================== +--- testdata/testinput2 (revision 1554) ++++ testdata/testinput2 (working copy) +@@ -1380,7 +1380,7 @@ + 1X + 123456\P + +-//KF>/dev/null ++//KF>testsavedregex + + /abc/IS>testsavedregex + 1)/ ++ + /-- End of testinput2 --/ +Index: testdata/testinput6 +=================================================================== +--- testdata/testinput6 (revision 1554) ++++ testdata/testinput6 (working copy) +@@ -1502,4 +1502,7 @@ + /\C\X*QT/8 + Ó…\x0aT + ++/[\pS#moq]/ ++ = ++ + /-- End of testinput6 --/ +Index: NON-AUTOTOOLS-BUILD +=================================================================== +--- NON-AUTOTOOLS-BUILD (revision 1554) ++++ NON-AUTOTOOLS-BUILD (working copy) +@@ -764,9 +764,9 @@ + + http://www.zaconsultants.net + +-There is also a mirror here: ++You may download PCRE from WWW.CBTTAPE.ORG, file 882.  Everything, source and ++executable, is in EBCDIC and native z/OS file formats and this is the ++recommended download site. + +- http://www.vsoft-software.com/downloads.html +- + ========================== +-Last Updated: 10 February 2015 ++Last Updated: 25 June 2015