[Pcre-svn] [914] code/trunk: Partial matching support is add…

Top Page
Delete this message
Author: Subversion repository
Date:  
To: pcre-svn
Subject: [Pcre-svn] [914] code/trunk: Partial matching support is added to the JIT compiler
Revision: 914
          http://vcs.pcre.org/viewvc?view=rev&revision=914
Author:   zherczeg
Date:     2012-02-13 06:04:50 +0000 (Mon, 13 Feb 2012)


Log Message:
-----------
Partial matching support is added to the JIT compiler

Modified Paths:
--------------
    code/trunk/ChangeLog
    code/trunk/pcre.h.in
    code/trunk/pcre_exec.c
    code/trunk/pcre_internal.h
    code/trunk/pcre_jit_compile.c
    code/trunk/pcre_jit_test.c
    code/trunk/pcre_study.c
    code/trunk/pcretest.c


Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog    2012-02-12 17:06:59 UTC (rev 913)
+++ code/trunk/ChangeLog    2012-02-13 06:04:50 UTC (rev 914)
@@ -12,7 +12,9 @@
     to unsigned type, result still unsigned" that was given by an MS compiler 
     on encountering the code "-sizeof(xxx)".


+4. Partial matching support is added to the JIT compiler.

+
Version 8.30 04-February-2012
-----------------------------


Modified: code/trunk/pcre.h.in
===================================================================
--- code/trunk/pcre.h.in    2012-02-12 17:06:59 UTC (rev 913)
+++ code/trunk/pcre.h.in    2012-02-13 06:04:50 UTC (rev 914)
@@ -254,7 +254,9 @@
 /* Request types for pcre_study(). Do not re-arrange, in order to remain
 compatible. */


-#define PCRE_STUDY_JIT_COMPILE            0x0001
+#define PCRE_STUDY_JIT_COMPILE                0x0001
+#define PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE   0x0002
+#define PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE   0x0004


/* Bit flags for the pcre[16]_extra structure. Do not re-arrange or redefine
these bits, just add new ones on the end, in order to remain compatible. */

Modified: code/trunk/pcre_exec.c
===================================================================
--- code/trunk/pcre_exec.c    2012-02-12 17:06:59 UTC (rev 913)
+++ code/trunk/pcre_exec.c    2012-02-13 06:04:50 UTC (rev 914)
@@ -6287,15 +6287,22 @@


 #ifdef SUPPORT_JIT
 if (extra_data != NULL
-    && (extra_data->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0
+    && (extra_data->flags & (PCRE_EXTRA_EXECUTABLE_JIT |
+                             PCRE_EXTRA_TABLES)) == PCRE_EXTRA_EXECUTABLE_JIT
     && extra_data->executable_jit != NULL
-    && (extra_data->flags & PCRE_EXTRA_TABLES) == 0
     && (options & ~(PCRE_NO_UTF8_CHECK | PCRE_NOTBOL | PCRE_NOTEOL |
-                    PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART)) == 0)
-  return PRIV(jit_exec)(re, extra_data->executable_jit,
+                    PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART |
+                    PCRE_PARTIAL_SOFT | PCRE_PARTIAL_HARD)) == 0)
+  {
+  rc = PRIV(jit_exec)(re, extra_data->executable_jit,
     (const pcre_uchar *)subject, length, start_offset, options,
     ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0)
     ? MATCH_LIMIT : extra_data->match_limit, offsets, offsetcount);
+  /* PCRE_ERROR_NULL means that the selected normal or partial matching
+  mode is not compiled. In this case we simply fallback to interpreter. */
+  if (rc != PCRE_ERROR_NULL)
+    return rc;
+  }
 #endif


/* Carry on with non-JIT matching. This information is for finding all the

Modified: code/trunk/pcre_internal.h
===================================================================
--- code/trunk/pcre_internal.h    2012-02-12 17:06:59 UTC (rev 913)
+++ code/trunk/pcre_internal.h    2012-02-13 06:04:50 UTC (rev 914)
@@ -887,7 +887,8 @@
    PCRE_NO_START_OPTIMIZE)


 #define PUBLIC_STUDY_OPTIONS \
-   PCRE_STUDY_JIT_COMPILE
+   (PCRE_STUDY_JIT_COMPILE|PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE| \
+    PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE)


/* Magic number to provide a small check against being handed junk. */

@@ -1941,6 +1942,10 @@
        ERR60, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69,
        ERR70, ERR71, ERR72, ERR73, ERR74, ERRCOUNT };


+/* JIT compiling modes. The function list is indexed by them. */
+enum { JIT_COMPILE, JIT_PARTIAL_SOFT_COMPILE, JIT_PARTIAL_HARD_COMPILE,
+       JIT_NUMBER_OF_COMPILE_TYPES };
+
 /* The real format of the start of the pcre block; the index of names and the
 code vector run on as long as necessary after the end. We store an explicit
 offset to the name table so that if a regex is compiled on one host, saved, and
@@ -2179,7 +2184,7 @@
 #define ctypes_offset (cbits_offset + cbit_length)
 #define tables_length (ctypes_offset + 256)


-/* Internal function prefix */
+/* Internal function and data prefixes. */

 #ifdef COMPILE_PCRE8
 #ifndef PUBL
@@ -2288,7 +2293,7 @@
 extern BOOL              PRIV(xclass)(int, const pcre_uchar *, BOOL);


 #ifdef SUPPORT_JIT
-extern void              PRIV(jit_compile)(const REAL_PCRE *, PUBL(extra) *);
+extern void              PRIV(jit_compile)(const REAL_PCRE *, PUBL(extra) *, int);
 extern int               PRIV(jit_exec)(const REAL_PCRE *, void *,
                            const pcre_uchar *, int, int, int, int, int *, int);
 extern void              PRIV(jit_free)(void *);


Modified: code/trunk/pcre_jit_compile.c
===================================================================
--- code/trunk/pcre_jit_compile.c    2012-02-12 17:06:59 UTC (rev 913)
+++ code/trunk/pcre_jit_compile.c    2012-02-13 06:04:50 UTC (rev 914)
@@ -162,12 +162,12 @@
   pcre_uint8 notempty_atstart;
 } jit_arguments;


-typedef struct executable_function {
- void *executable_func;
+typedef struct executable_functions {
+ void *executable_funcs[JIT_NUMBER_OF_COMPILE_TYPES];
PUBL(jit_callback) callback;
void *userdata;
- sljit_uw executable_size;
-} executable_function;
+ sljit_uw executable_sizes[JIT_NUMBER_OF_COMPILE_TYPES];
+} executable_functions;

 typedef struct jump_list {
   struct sljit_jump *jump;
@@ -275,6 +275,7 @@
   const pcre_uint8 *fcc;
   sljit_w lcc;
   int cbraptr;
+  int mode;
   int nltype;
   int newline;
   int bsr_nltype;
@@ -283,10 +284,12 @@
   sljit_uw name_table;
   sljit_w name_count;
   sljit_w name_entry_size;
+  struct sljit_label *partialmatchlabel;
   struct sljit_label *acceptlabel;
   stub_list *stubs;
   recurse_entry *entries;
   recurse_entry *currententry;
+  jump_list *partialmatch;
   jump_list *accept;
   jump_list *calllimit;
   jump_list *stackalloc;
@@ -380,15 +383,21 @@
 #define RECURSIVE_HEAD   (4 * sizeof(sljit_w))
 /* Max limit of recursions. */
 #define CALL_LIMIT       (5 * sizeof(sljit_w))
-/* Last known position of the requested byte. */
+/* Last known position of the requested byte.
+Same as START_USED_PTR. (Partial matching and req_char are exclusive) */
 #define REQ_CHAR_PTR     (6 * sizeof(sljit_w))
+/* First inspected character for partial matching.
+Same as REQ_CHAR_PTR. (Partial matching and req_char are exclusive) */
+#define START_USED_PTR   (6 * sizeof(sljit_w))
+/* Starting pointer for partial soft matches. */
+#define HIT_START        (8 * sizeof(sljit_w))
 /* End pointer of the first line. */
-#define FIRSTLINE_END    (7 * sizeof(sljit_w))
+#define FIRSTLINE_END    (9 * sizeof(sljit_w))
 /* The output vector is stored on the stack, and contains pointers
 to characters. The vector data is divided into two groups: the first
 group contains the start / end character pointers, and the second is
 the start pointers when the end of the capturing group has not yet reached. */
-#define OVECTOR_START    (8 * sizeof(sljit_w))
+#define OVECTOR_START    (10 * sizeof(sljit_w))
 #define OVECTOR(i)       (OVECTOR_START + (i) * sizeof(sljit_w))
 #define OVECTOR_PRIV(i)  (common->cbraptr + (i) * sizeof(sljit_w))
 #define PRIV_DATA(cc)    (common->localptrs[(cc) - common->start])
@@ -1268,6 +1277,60 @@
   OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1);
 }


+static SLJIT_INLINE void return_with_partial_match(compiler_common *common, struct sljit_label *leave)
+{
+DEFINE_COMPILER;
+
+SLJIT_COMPILE_ASSERT(STR_END == SLJIT_SAVED_REG2, str_end_must_be_saved_reg2);
+
+OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG2, 0, ARGUMENTS, 0);
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_PARTIAL);
+OP1(SLJIT_MOV_SI, SLJIT_TEMPORARY_REG3, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), SLJIT_OFFSETOF(jit_arguments, offsetcount));
+CMPTO(SLJIT_C_LESS, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, 2, leave);
+
+/* Store match begin and end. */
+OP1(SLJIT_MOV, SLJIT_SAVED_REG1, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), SLJIT_OFFSETOF(jit_arguments, begin));
+OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG2, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), SLJIT_OFFSETOF(jit_arguments, offsets));
+OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG3, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mode == JIT_PARTIAL_HARD_COMPILE ? START_USED_PTR : HIT_START);
+OP2(SLJIT_SUB, SLJIT_SAVED_REG2, 0, STR_END, 0, SLJIT_SAVED_REG1, 0);
+#ifdef COMPILE_PCRE16
+OP2(SLJIT_ASHR, SLJIT_SAVED_REG2, 0, SLJIT_SAVED_REG2, 0, SLJIT_IMM, 1);
+#endif
+OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), sizeof(int), SLJIT_SAVED_REG2, 0);
+
+OP2(SLJIT_SUB, SLJIT_TEMPORARY_REG3, 0, SLJIT_TEMPORARY_REG3, 0, SLJIT_SAVED_REG1, 0);
+#ifdef COMPILE_PCRE16
+OP2(SLJIT_ASHR, SLJIT_TEMPORARY_REG3, 0, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, 1);
+#endif
+OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), 0, SLJIT_TEMPORARY_REG3, 0);
+
+JUMPTO(SLJIT_JUMP, leave);
+}
+
+static SLJIT_INLINE void check_start_used_ptr(compiler_common *common)
+{
+/* May destroy TMP1. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
+ {
+ /* The value of -1 must be kept for START_USED_PTR! */
+ OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, SLJIT_IMM, 1);
+ /* Jumps if START_USED_PTR < STR_PTR, or START_USED_PTR == -1. Although overwriting
+ is not necessary if START_USED_PTR == STR_PTR, it does not hurt as well. */
+ jump = CMP(SLJIT_C_LESS_EQUAL, TMP1, 0, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, STR_PTR, 0);
+ JUMPHERE(jump);
+ }
+else if (common->mode == JIT_PARTIAL_HARD_COMPILE)
+ {
+ jump = CMP(SLJIT_C_LESS_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, STR_PTR, 0);
+ JUMPHERE(jump);
+ }
+}
+
static SLJIT_INLINE BOOL char_has_othercase(compiler_common *common, pcre_uchar* cc)
{
/* Detects if the character has an othercase. */
@@ -1389,12 +1452,87 @@
#endif /* COMPILE_PCRE8 */
}

-static SLJIT_INLINE void check_input_end(compiler_common *common, jump_list **fallbacks)
+static void check_partial(compiler_common *common)
 {
 DEFINE_COMPILER;
-add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+struct sljit_jump *jump;
+
+if (common->mode == JIT_COMPILE)
+  return;
+
+jump = CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, STR_PTR, 0);
+if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), HIT_START, SLJIT_IMM, -1);
+else
+  {
+  if (common->partialmatchlabel != NULL)
+    JUMPTO(SLJIT_JUMP, common->partialmatchlabel);
+  else
+    add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP));
+  }
+JUMPHERE(jump);
 }


+static struct sljit_jump *check_str_end(compiler_common *common)
+{
+/* Does not affect registers. Usually used in a tight spot. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_jump *nohit;
+struct sljit_jump *return_value;
+
+if (common->mode == JIT_COMPILE)
+  return CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+
+jump = CMP(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0);
+if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
+  {
+  nohit = CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, STR_PTR, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), HIT_START, SLJIT_IMM, -1);
+  JUMPHERE(nohit);
+  return_value = JUMP(SLJIT_JUMP);
+  }
+else
+  {
+  return_value = CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, STR_PTR, 0);
+  if (common->partialmatchlabel != NULL)
+    JUMPTO(SLJIT_JUMP, common->partialmatchlabel);
+  else
+    add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP));
+  }
+JUMPHERE(jump);
+return return_value;
+}
+
+static void fallback_at_str_end(compiler_common *common, jump_list **fallbacks)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (common->mode == JIT_COMPILE)
+  {
+  add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+  return;
+  }
+
+/* Partial matching mode. */
+jump = CMP(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0);
+add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, STR_PTR, 0));
+if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
+  {
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), HIT_START, SLJIT_IMM, -1);
+  add_jump(compiler, fallbacks, JUMP(SLJIT_JUMP));
+  }
+else
+  {
+  if (common->partialmatchlabel != NULL)
+    JUMPTO(SLJIT_JUMP, common->partialmatchlabel);
+  else
+    add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP));
+  }
+JUMPHERE(jump);
+}
+
 static void read_char(compiler_common *common)
 {
 /* Reads the character into TMP1, updates STR_PTR.
@@ -2162,7 +2300,7 @@
 static void check_wordboundary(compiler_common *common)
 {
 DEFINE_COMPILER;
-struct sljit_jump *beginend;
+struct sljit_jump *skipread;
 #if !(defined COMPILE_PCRE8) || defined SUPPORT_UTF
 struct sljit_jump *jump;
 #endif
@@ -2174,8 +2312,9 @@
 OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
 OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
 OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, SLJIT_IMM, 0);
-beginend = CMP(SLJIT_C_LESS_EQUAL, STR_PTR, 0, TMP1, 0);
+skipread = CMP(SLJIT_C_LESS_EQUAL, STR_PTR, 0, TMP1, 0);
 skip_char_back(common);
+check_start_used_ptr(common);
 read_char(common);


 /* Testing char type. */
@@ -2216,10 +2355,10 @@
     JUMPHERE(jump);
 #endif /* COMPILE_PCRE8 */
   }
-JUMPHERE(beginend);
+JUMPHERE(skipread);


OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
-beginend = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+skipread = check_str_end(common);
peek_char(common);

 /* Testing char type. This is a code duplication. */
@@ -2260,7 +2399,7 @@
     JUMPHERE(jump);
 #endif /* COMPILE_PCRE8 */
   }
-JUMPHERE(beginend);
+JUMPHERE(skipread);


OP2(SLJIT_XOR | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1);
sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0);
@@ -2660,7 +2799,7 @@
unsigned int charoffset;

/* Although SUPPORT_UTF must be defined, we are not necessary in utf mode. */
-check_input_end(common, fallbacks);
+fallback_at_str_end(common, fallbacks);
read_char(common);

if ((*cc++ & XCL_MAP) != 0)
@@ -3014,7 +3153,7 @@

case OP_NOT_DIGIT:
case OP_DIGIT:
- check_input_end(common, fallbacks);
+ fallback_at_str_end(common, fallbacks);
read_char8_type(common);
OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit);
add_jump(compiler, fallbacks, JUMP(type == OP_DIGIT ? SLJIT_C_ZERO : SLJIT_C_NOT_ZERO));
@@ -3022,7 +3161,7 @@

case OP_NOT_WHITESPACE:
case OP_WHITESPACE:
- check_input_end(common, fallbacks);
+ fallback_at_str_end(common, fallbacks);
read_char8_type(common);
OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_space);
add_jump(compiler, fallbacks, JUMP(type == OP_WHITESPACE ? SLJIT_C_ZERO : SLJIT_C_NOT_ZERO));
@@ -3030,14 +3169,14 @@

case OP_NOT_WORDCHAR:
case OP_WORDCHAR:
- check_input_end(common, fallbacks);
+ fallback_at_str_end(common, fallbacks);
read_char8_type(common);
OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_word);
add_jump(compiler, fallbacks, JUMP(type == OP_WORDCHAR ? SLJIT_C_ZERO : SLJIT_C_NOT_ZERO));
return cc;

   case OP_ANY:
-  check_input_end(common, fallbacks);
+  fallback_at_str_end(common, fallbacks);
   read_char(common);
   if (common->nltype == NLTYPE_FIXED && common->newline > 255)
     {
@@ -3053,7 +3192,7 @@
   return cc;


   case OP_ALLANY:
-  check_input_end(common, fallbacks);
+  fallback_at_str_end(common, fallbacks);
 #ifdef SUPPORT_UTF
   if (common->utf)
     {
@@ -3081,7 +3220,7 @@
   return cc;


case OP_ANYBYTE:
- check_input_end(common, fallbacks);
+ fallback_at_str_end(common, fallbacks);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
return cc;

@@ -3100,7 +3239,7 @@
#endif

case OP_ANYNL:
- check_input_end(common, fallbacks);
+ fallback_at_str_end(common, fallbacks);
read_char(common);
jump[0] = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
jump[1] = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
@@ -3117,7 +3256,7 @@

case OP_NOT_HSPACE:
case OP_HSPACE:
- check_input_end(common, fallbacks);
+ fallback_at_str_end(common, fallbacks);
read_char(common);
add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL));
add_jump(compiler, fallbacks, JUMP(type == OP_NOT_HSPACE ? SLJIT_C_NOT_ZERO : SLJIT_C_ZERO));
@@ -3125,7 +3264,7 @@

case OP_NOT_VSPACE:
case OP_VSPACE:
- check_input_end(common, fallbacks);
+ fallback_at_str_end(common, fallbacks);
read_char(common);
add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL));
add_jump(compiler, fallbacks, JUMP(type == OP_NOT_VSPACE ? SLJIT_C_NOT_ZERO : SLJIT_C_ZERO));
@@ -3133,7 +3272,7 @@

 #ifdef SUPPORT_UCP
   case OP_EXTUNI:
-  check_input_end(common, fallbacks);
+  fallback_at_str_end(common, fallbacks);
   read_char(common);
   add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
   OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Mc);
@@ -3203,10 +3342,12 @@
     JUMPHERE(jump[3]);
     }
   JUMPHERE(jump[0]);
+  check_partial(common);
   return cc;


case OP_EOD:
add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
+ check_partial(common);
return cc;

case OP_CIRC:
@@ -3226,7 +3367,7 @@
jump[0] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[1]);

-  add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, STR_PTR, 0, STR_END, 0));
+  add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
   if (common->nltype == NLTYPE_FIXED && common->newline > 255)
     {
     OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
@@ -3253,7 +3394,10 @@
   if (!common->endonly)
     compile_char1_hotpath(common, OP_EODN, cc, fallbacks);
   else
+    {
     add_jump(compiler, fallbacks, CMP(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0));
+    check_partial(common);
+    }
   return cc;


case OP_DOLLM:
@@ -3261,6 +3405,7 @@
OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol));
add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ check_partial(common);
jump[0] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[1]);

@@ -3287,7 +3432,7 @@
 #ifdef SUPPORT_UTF
   if (common->utf && HAS_EXTRALEN(*cc)) length += GET_EXTRALEN(*cc);
 #endif
-  if (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0)
+  if (common->mode == JIT_COMPILE && (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0))
     {
     OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
     add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER, STR_PTR, 0, STR_END, 0));
@@ -3299,7 +3444,7 @@
 #endif
     return byte_sequence_compare(common, type == OP_CHARI, cc, &context, fallbacks);
     }
-  check_input_end(common, fallbacks);
+  fallback_at_str_end(common, fallbacks);
   read_char(common);
 #ifdef SUPPORT_UTF
   if (common->utf)
@@ -3309,6 +3454,19 @@
   else
 #endif
     c = *cc;
+  if (type == OP_CHAR || !char_has_othercase(common, cc))
+    {
+    add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, c));
+    return cc + length;
+    }
+  oc = char_othercase(common, c);
+  bit = c ^ oc;
+  if (ispowerof2(bit))
+    {
+    OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit);
+    add_jump(compiler, fallbacks, CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, c | bit));
+    return cc + length;
+    }
   OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c);
   COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL);
   OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char_othercase(common, c));
@@ -3318,7 +3476,7 @@


case OP_NOT:
case OP_NOTI:
- check_input_end(common, fallbacks);
+ fallback_at_str_end(common, fallbacks);
length = 1;
#ifdef SUPPORT_UTF
if (common->utf)
@@ -3379,7 +3537,7 @@

   case OP_CLASS:
   case OP_NCLASS:
-  check_input_end(common, fallbacks);
+  fallback_at_str_end(common, fallbacks);
   read_char(common);
 #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
   jump[0] = NULL;
@@ -3429,12 +3587,15 @@
     skip_char_back(common);
     OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
     JUMPTO(SLJIT_C_NOT_ZERO, label);
-    return cc + LINK_SIZE;
     }
+  else
 #endif
-  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
-  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
-  add_jump(compiler, fallbacks, CMP(SLJIT_C_LESS, STR_PTR, 0, TMP1, 0));
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+    OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
+    add_jump(compiler, fallbacks, CMP(SLJIT_C_LESS, STR_PTR, 0, TMP1, 0));
+    }
+  check_start_used_ptr(common);
   return cc + LINK_SIZE;
   }
 SLJIT_ASSERT_STOP();
@@ -3517,6 +3678,7 @@
   {
   if (fallbacks == NULL)
     {
+    /* OVECTOR(1) contains the "string begin - 1" constant. */
     OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1));
     COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL);
     OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1));
@@ -3558,7 +3720,7 @@
     } \
   while (0)


-#define FALLBACK_AS(type) ((type*)fallback)
+#define FALLBACK_AS(type) ((type *)fallback)

static pcre_uchar *compile_ref_hotpath(compiler_common *common, pcre_uchar *cc, jump_list **fallbacks, BOOL withchecks, BOOL emptyfail)
{
@@ -3567,6 +3729,7 @@
struct sljit_jump *jump = NULL;

OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset));
+/* OVECTOR(1) contains the "string begin - 1" constant. */
if (withchecks && !common->jscript_compat)
add_jump(compiler, fallbacks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1)));

@@ -3578,6 +3741,9 @@
   if (withchecks)
     jump = CMP(SLJIT_C_EQUAL, TMP1, 0, TMP2, 0);


+  if (common->mode != JIT_COMPILE)
+    fallback_at_str_end(common, fallbacks);
+
   /* Needed to save important temporary registers. */
   OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, STACK_TOP, 0);
   OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG2, 0, ARGUMENTS, 0);
@@ -3593,6 +3759,10 @@
   OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP1, 0);
   if (withchecks)
     jump = JUMP(SLJIT_C_ZERO);
+
+  if (common->mode != JIT_COMPILE)
+    fallback_at_str_end(common, fallbacks);
+
   OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);


   add_jump(compiler, fallbacks, CMP(SLJIT_C_GREATER, STR_PTR, 0, STR_END, 0));
@@ -4644,7 +4814,7 @@
 if (bra == OP_BRAMINZERO)
   {
   /* This is a fallback path! (From the viewpoint of OP_BRAMINZERO) */
-  JUMPTO(SLJIT_JUMP, ((braminzero_fallback*)parent)->hotpath);
+  JUMPTO(SLJIT_JUMP, ((braminzero_fallback *)parent)->hotpath);
   if (braminzerojump != NULL)
     {
     JUMPHERE(braminzerojump);
@@ -5264,7 +5434,10 @@


     case OP_CHAR:
     case OP_CHARI:
-    cc = compile_charn_hotpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextfallbacks : &parent->topfallbacks);
+    if (common->mode == JIT_COMPILE)
+      cc = compile_charn_hotpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextfallbacks : &parent->topfallbacks);
+    else
+      cc = compile_char1_hotpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextfallbacks : &parent->topfallbacks);
     break;


     case OP_STAR:
@@ -5457,7 +5630,7 @@
     } \
   while (0)


-#define CURRENT_AS(type) ((type*)current)
+#define CURRENT_AS(type) ((type *)current)

static void compile_iterator_fallbackpath(compiler_common *common, struct fallback_common *current)
{
@@ -6358,7 +6531,7 @@
#undef CURRENT_AS

void
-PRIV(jit_compile)(const REAL_PCRE *re, PUBL(extra) *extra)
+PRIV(jit_compile)(const REAL_PCRE *re, PUBL(extra) *extra, int mode)
{
struct sljit_compiler *compiler;
fallback_common rootfallback;
@@ -6367,14 +6540,14 @@
const pcre_uint8 *tables = re->tables;
pcre_study_data *study;
pcre_uchar *ccend;
-executable_function *function;
+executable_functions *functions;
void *executable_func;
sljit_uw executable_size;
struct sljit_label *leave;
struct sljit_label *mainloop = NULL;
struct sljit_label *empty_match_found;
struct sljit_label *empty_match_fallback;
-struct sljit_jump *alloc_error;
+struct sljit_jump *jump;
struct sljit_jump *reqbyte_notfound = NULL;
struct sljit_jump *empty_match;

@@ -6392,6 +6565,7 @@
common->cbraptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_w);
common->fcc = tables + fcc_offset;
common->lcc = (sljit_w)(tables + lcc_offset);
+common->mode = mode;
common->nltype = NLTYPE_FIXED;
switch(re->options & PCRE_NEWLINE_BITS)
{
@@ -6429,10 +6603,12 @@
common->name_table = (sljit_w)((pcre_uchar *)re + re->name_table_offset);
common->name_count = re->name_count;
common->name_entry_size = re->name_entry_size;
+common->partialmatchlabel = NULL;
common->acceptlabel = NULL;
common->stubs = NULL;
common->entries = NULL;
common->currententry = NULL;
+common->partialmatch = NULL;
common->accept = NULL;
common->calllimit = NULL;
common->stackalloc = NULL;
@@ -6466,7 +6642,7 @@
common->localsize += common->cbraptr + (re->top_bracket + 1) * sizeof(sljit_w);
if (common->localsize > SLJIT_MAX_LOCAL_SIZE)
return;
-common->localptrs = (int*)SLJIT_MALLOC((ccend - rootfallback.cc) * sizeof(int));
+common->localptrs = (int *)SLJIT_MALLOC((ccend - rootfallback.cc) * sizeof(int));
if (!common->localptrs)
return;
memset(common->localptrs, 0, (ccend - rootfallback.cc) * sizeof(int));
@@ -6485,7 +6661,7 @@

/* Register init. */
reset_ovector(common, (re->top_bracket + 1) * 2);
-if ((re->flags & PCRE_REQCHSET) != 0)
+if (mode == JIT_COMPILE && (re->flags & PCRE_REQCHSET) != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), REQ_CHAR_PTR, SLJIT_TEMPORARY_REG1, 0);

OP1(SLJIT_MOV, ARGUMENTS, 0, SLJIT_SAVED_REG1, 0);
@@ -6498,6 +6674,9 @@
OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, limit));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CALL_LIMIT, TMP1, 0);

+if (mode == JIT_PARTIAL_SOFT_COMPILE)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), HIT_START, SLJIT_IMM, 0);
+
 /* Main part of the matching */
 if ((re->options & PCRE_ANCHORED) == 0)
   {
@@ -6510,13 +6689,22 @@
   else if ((re->flags & PCRE_STARTLINE) == 0 && study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0)
     fast_forward_start_bits(common, (sljit_uw)study->start_bits, (re->options & PCRE_FIRSTLINE) != 0);
   }
-if ((re->flags & PCRE_REQCHSET) != 0)
+if (mode == JIT_COMPILE && (re->flags & PCRE_REQCHSET) != 0)
   reqbyte_notfound = search_requested_char(common, (pcre_uchar)re->req_char, (re->flags & PCRE_RCH_CASELESS) != 0, (re->flags & PCRE_FIRSTSET) != 0);


/* Store the current STR_PTR in OVECTOR(0). */
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), STR_PTR, 0);
/* Copy the limit of allowed recursions. */
OP1(SLJIT_MOV, CALL_COUNT, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CALL_LIMIT);
+/* Copy the beginning of the string. */
+if (mode == JIT_PARTIAL_SOFT_COMPILE)
+ {
+ jump = CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), HIT_START, SLJIT_IMM, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, STR_PTR, 0);
+ JUMPHERE(jump);
+ }
+else if (mode == JIT_PARTIAL_HARD_COMPILE)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, STR_PTR, 0);

compile_hotpath(common, rootfallback.cc, ccend, &rootfallback);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
@@ -6538,6 +6726,13 @@
leave = LABEL();
sljit_emit_return(compiler, SLJIT_MOV, SLJIT_RETURN_REG, 0);

+if (mode != JIT_COMPILE)
+ {
+ common->partialmatchlabel = LABEL();
+ set_jumps(common->partialmatch, common->partialmatchlabel);
+ return_with_partial_match(common, leave);
+ }
+
empty_match_fallback = LABEL();
compile_fallbackpath(common, rootfallback.top);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
@@ -6549,6 +6744,15 @@

SLJIT_ASSERT(rootfallback.prev == NULL);

+if (mode == JIT_PARTIAL_SOFT_COMPILE)
+ {
+ jump = CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), HIT_START, SLJIT_IMM, -1);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), START_USED_PTR, SLJIT_IMM, -1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), HIT_START, TMP1, 0);
+ JUMPHERE(jump);
+ }
+
/* Check we have remaining characters. */
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0));

@@ -6556,7 +6760,7 @@
   {
   if ((re->options & PCRE_FIRSTLINE) == 0)
     {
-    if (study != NULL && study->minlength > 1)
+    if (mode == JIT_COMPILE && study != NULL && study->minlength > 1)
       {
       OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(study->minlength));
       CMPTO(SLJIT_C_LESS_EQUAL, TMP1, 0, STR_END, 0, mainloop);
@@ -6566,7 +6770,7 @@
     }
   else
     {
-    if (study != NULL && study->minlength > 1)
+    if (mode == JIT_COMPILE && study != NULL && study->minlength > 1)
       {
       OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(study->minlength));
       OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, STR_END, 0);
@@ -6580,10 +6784,13 @@
     }
   }


+/* No more remaining characters. */
if (reqbyte_notfound != NULL)
JUMPHERE(reqbyte_notfound);
-/* Copy OVECTOR(1) to OVECTOR(0) */
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1));
+
+if (mode == JIT_PARTIAL_SOFT_COMPILE)
+ CMPTO(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), HIT_START, SLJIT_IMM, 0, common->partialmatchlabel);
+
OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH);
JUMPTO(SLJIT_JUMP, leave);

@@ -6626,7 +6833,7 @@
OP2(SLJIT_ADD, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit), SLJIT_IMM, STACK_GROWTH_RATE);

sljit_emit_ijump(compiler, SLJIT_CALL2, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize));
-alloc_error = CMP(SLJIT_C_NOT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+jump = CMP(SLJIT_C_NOT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, top));
@@ -6635,7 +6842,7 @@
sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0);

/* Allocation failed. */
-JUMPHERE(alloc_error);
+JUMPHERE(jump);
/* We break the return address cache here, but this is a really rare case. */
OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_JIT_STACKLIMIT);
JUMPTO(SLJIT_JUMP, leave);
@@ -6709,24 +6916,29 @@
if (executable_func == NULL)
return;

-function = SLJIT_MALLOC(sizeof(executable_function));
-if (function == NULL)
+/* Reuse the function descriptor if possible. */
+if ((extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 && extra->executable_jit != NULL)
+  functions = (executable_functions *)extra->executable_jit;
+else
   {
-  /* This case is highly unlikely since we just recently
-  freed a lot of memory. Although not impossible. */
-  sljit_free_code(executable_func);
-  return;
+  functions = SLJIT_MALLOC(sizeof(executable_functions));
+  if (functions == NULL)
+    {
+    /* This case is highly unlikely since we just recently
+    freed a lot of memory. Although not impossible. */
+    sljit_free_code(executable_func);
+    return;
+    }
+  memset(functions, 0, sizeof(executable_functions));
+  extra->executable_jit = functions;
+  extra->flags |= PCRE_EXTRA_EXECUTABLE_JIT;
   }


-function->executable_func = executable_func;
-function->executable_size = executable_size;
-function->callback = NULL;
-function->userdata = NULL;
-extra->executable_jit = function;
-extra->flags |= PCRE_EXTRA_EXECUTABLE_JIT;
+functions->executable_funcs[mode] = executable_func;
+functions->executable_sizes[mode] = executable_size;
}

-static int jit_machine_stack_exec(jit_arguments *arguments, executable_function *function)
+static int jit_machine_stack_exec(jit_arguments *arguments, void* executable_func)
 {
 union {
    void* executable_func;
@@ -6740,16 +6952,16 @@
 local_stack.limit = local_stack.base + LOCAL_SPACE_SIZE;
 local_stack.max_limit = local_stack.limit;
 arguments->stack = &local_stack;
-convert_executable_func.executable_func = function->executable_func;
+convert_executable_func.executable_func = executable_func;
 return convert_executable_func.call_executable_func(arguments);
 }


 int
-PRIV(jit_exec)(const REAL_PCRE *re, void *executable_func,
+PRIV(jit_exec)(const REAL_PCRE *re, void *executable_funcs,
   const pcre_uchar *subject, int length, int start_offset, int options,
   int match_limit, int *offsets, int offsetcount)
 {
-executable_function *function = (executable_function*)executable_func;
+executable_functions *functions = (executable_functions *)executable_funcs;
 union {
    void* executable_func;
    jit_function call_executable_func;
@@ -6757,7 +6969,16 @@
 jit_arguments arguments;
 int maxoffsetcount;
 int retval;
+int mode = JIT_COMPILE;


+if ((options & PCRE_PARTIAL_HARD) != 0)
+ mode = JIT_PARTIAL_HARD_COMPILE;
+else if ((options & PCRE_PARTIAL_SOFT) != 0)
+ mode = JIT_PARTIAL_SOFT_COMPILE;
+
+if (functions->executable_funcs[mode] == NULL)
+ return PCRE_ERROR_NULL;
+
/* Sanity checks should be handled by pcre_exec. */
arguments.stack = NULL;
arguments.str = subject + start_offset;
@@ -6783,16 +7004,16 @@
offsetcount = maxoffsetcount;
arguments.offsetcount = offsetcount;

-if (function->callback)
- arguments.stack = (struct sljit_stack*)function->callback(function->userdata);
+if (functions->callback)
+ arguments.stack = (struct sljit_stack *)functions->callback(functions->userdata);
else
- arguments.stack = (struct sljit_stack*)function->userdata;
+ arguments.stack = (struct sljit_stack *)functions->userdata;

if (arguments.stack == NULL)
- retval = jit_machine_stack_exec(&arguments, function);
+ retval = jit_machine_stack_exec(&arguments, functions->executable_funcs[mode]);
else
{
- convert_executable_func.executable_func = function->executable_func;
+ convert_executable_func.executable_func = functions->executable_funcs[mode];
retval = convert_executable_func.call_executable_func(&arguments);
}

@@ -6802,17 +7023,22 @@
}

 void
-PRIV(jit_free)(void *executable_func)
+PRIV(jit_free)(void *executable_funcs)
 {
-executable_function *function = (executable_function*)executable_func;
-sljit_free_code(function->executable_func);
-SLJIT_FREE(function);
+int i;
+executable_functions *functions = (executable_functions *)executable_funcs;
+for (i = 0; i < JIT_NUMBER_OF_COMPILE_TYPES; i++)
+  {
+  if (functions->executable_funcs[i] != NULL)
+    sljit_free_code(functions->executable_funcs[i]);
+  }
+SLJIT_FREE(functions);
 }


int
-PRIV(jit_get_size)(void *executable_func)
+PRIV(jit_get_size)(void *executable_funcs)
{
-return ((executable_function*)executable_func)->executable_size;
+return ((executable_functions *)executable_funcs)->executable_sizes[PCRE_STUDY_JIT_COMPILE];
}

const char*
@@ -6846,7 +7072,7 @@
pcre16_jit_stack_free(pcre16_jit_stack *stack)
#endif
{
-sljit_free_stack((struct sljit_stack*)stack);
+sljit_free_stack((struct sljit_stack *)stack);
}

 #ifdef COMPILE_PCRE8
@@ -6857,14 +7083,14 @@
 pcre16_assign_jit_stack(pcre16_extra *extra, pcre16_jit_callback callback, void *userdata)
 #endif
 {
-executable_function *function;
+executable_functions *functions;
 if (extra != NULL &&
     (extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 &&
     extra->executable_jit != NULL)
   {
-  function = (executable_function*)extra->executable_jit;
-  function->callback = callback;
-  function->userdata = userdata;
+  functions = (executable_functions *)extra->executable_jit;
+  functions->callback = callback;
+  functions->userdata = userdata;
   }
 }



Modified: code/trunk/pcre_jit_test.c
===================================================================
--- code/trunk/pcre_jit_test.c    2012-02-12 17:06:59 UTC (rev 913)
+++ code/trunk/pcre_jit_test.c    2012-02-13 06:04:50 UTC (rev 914)
@@ -653,6 +653,16 @@
     { 0, 0 | F_NO8 | F_FORCECONV, "\\v+?\\V+?#", "\xe2\x80\xa9\xe2\x80\xa9\xef\xbf\xbf\xef\xbf\xbf#" },
     { 0, 0 | F_NO8 | F_FORCECONV, "\\h+?\\H+?#", "\xe1\xa0\x8e\xe1\xa0\x8e\xef\xbf\xbf\xef\xbf\xbf#" },


+    /* Partial matching. */
+    { MUA | PCRE_PARTIAL_SOFT, 0, "ab", "a" },
+    { MUA | PCRE_PARTIAL_SOFT, 0, "ab|a", "a" },
+    { MUA | PCRE_PARTIAL_HARD, 0, "ab|a", "a" },
+    { MUA | PCRE_PARTIAL_SOFT, 0, "\\b#", "a" },
+    { MUA | PCRE_PARTIAL_SOFT, 0, "(?<=a)b", "a" },
+    { MUA | PCRE_PARTIAL_SOFT, 0, "abc|(?<=xxa)bc", "xxab" },
+    { MUA | PCRE_PARTIAL_SOFT, 0, "a\\B", "a" },
+    { MUA | PCRE_PARTIAL_HARD, 0, "a\\b", "a" },
+
     /* Deep recursion. */
     { MUA, 0, "((((?:(?:(?:\\w)+)?)*|(?>\\w)+?)+|(?>\\w)?\?)*)?\\s", "aaaaa+ " },
     { MUA, 0, "(?:((?:(?:(?:\\w*?)+)??|(?>\\w)?|\\w*+)*)+)+?\\s", "aa+ " },
@@ -867,6 +877,7 @@
     int total = 0;
     int successful = 0;
     int counter = 0;
+    int study_mode;
 #ifdef SUPPORT_PCRE8
     pcre *re8;
     pcre_extra *extra8;
@@ -930,18 +941,24 @@
             is_ascii_input = check_ascii(current->input);
         }


+        if (current->flags & PCRE_PARTIAL_SOFT)
+            study_mode = PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE;
+        else if (current->flags & PCRE_PARTIAL_HARD)
+            study_mode = PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE;
+        else
+            study_mode = PCRE_STUDY_JIT_COMPILE;
         error = NULL;
 #ifdef SUPPORT_PCRE8
         re8 = NULL;
         if (!(current->start_offset & F_NO8))
             re8 = pcre_compile(current->pattern,
-                current->flags & ~(PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | disabled_flags8),
+                current->flags & ~(PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | PCRE_PARTIAL_SOFT | PCRE_PARTIAL_HARD | disabled_flags8),
                 &error, &err_offs, tables(0));


         extra8 = NULL;
         if (re8) {
             error = NULL;
-            extra8 = pcre_study(re8, PCRE_STUDY_JIT_COMPILE, &error);
+            extra8 = pcre_study(re8, study_mode, &error);
             if (!extra8) {
                 printf("\n8 bit: Cannot study pattern: %s\n", current->pattern);
                 pcre_free(re8);
@@ -965,13 +982,13 @@
         re16 = NULL;
         if (!(current->start_offset & F_NO16))
             re16 = pcre16_compile(regtest_buf,
-                current->flags & ~(PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | disabled_flags16),
+                current->flags & ~(PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | PCRE_PARTIAL_SOFT | PCRE_PARTIAL_HARD | disabled_flags16),
                 &error, &err_offs, tables(0));


         extra16 = NULL;
         if (re16) {
             error = NULL;
-            extra16 = pcre16_study(re16, PCRE_STUDY_JIT_COMPILE, &error);
+            extra16 = pcre16_study(re16, study_mode, &error);
             if (!extra16) {
                 printf("\n16 bit: Cannot study pattern: %s\n", current->pattern);
                 pcre16_free(re16);
@@ -1007,9 +1024,9 @@
         if (re8) {
             setstack8(extra8);
             return_value8_1 = pcre_exec(re8, extra8, current->input, strlen(current->input), current->start_offset & OFFSET_MASK,
-                current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART), ovector8_1, 32);
+                current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | PCRE_PARTIAL_SOFT | PCRE_PARTIAL_HARD), ovector8_1, 32);
             return_value8_2 = pcre_exec(re8, NULL, current->input, strlen(current->input), current->start_offset & OFFSET_MASK,
-                current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART), ovector8_2, 32);
+                current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | PCRE_PARTIAL_SOFT | PCRE_PARTIAL_HARD), ovector8_2, 32);
         }
 #endif


@@ -1027,12 +1044,14 @@
             else
                 length16 = copy_char8_to_char16(current->input, regtest_buf, REGTEST_MAX_LENGTH);
             return_value16_1 = pcre16_exec(re16, extra16, regtest_buf, length16, current->start_offset & OFFSET_MASK,
-                current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART), ovector16_1, 32);
+                current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | PCRE_PARTIAL_SOFT | PCRE_PARTIAL_HARD), ovector16_1, 32);
             return_value16_2 = pcre16_exec(re16, NULL, regtest_buf, length16, current->start_offset & OFFSET_MASK,
-                current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART), ovector16_2, 32);
+                current->flags & (PCRE_NOTBOL | PCRE_NOTEOL | PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | PCRE_PARTIAL_SOFT | PCRE_PARTIAL_HARD), ovector16_2, 32);
         }
 #endif


+        /* printf("[%d-%d|%d-%d|%d-%d]%s", return_value8_1, return_value16_1, ovector8_1[0], ovector8_1[1], ovector16_1[0], ovector16_1[1], (current->flags & PCRE_CASELESS) ? "C" : ""); */
+
         /* If F_DIFF is set, just run the test, but do not compare the results.
         Segfaults can still be captured. */


@@ -1046,8 +1065,15 @@
                         return_value8_1, return_value8_2, return_value16_1, return_value16_2,
                         total, current->pattern, current->input);
                     is_successful = 0;
-                } else if (return_value8_1 >= 0) {
-                    return_value8_1 *= 2;
+                } else if (return_value8_1 >= 0 || return_value8_1 == PCRE_ERROR_PARTIAL) {
+                    if (return_value8_1 == PCRE_ERROR_PARTIAL) {
+                        return_value8_1 = 2;
+                        return_value16_1 = 2;
+                    } else {
+                        return_value8_1 *= 2;
+                        return_value16_1 *= 2;
+                    }
+
                     /* Transform back the results. */
                     if (current->flags & PCRE_UTF8) {
                         for (i = 0; i < return_value8_1; ++i) {
@@ -1074,8 +1100,12 @@
                     printf("\n8 bit: Return value differs(%d:%d): [%d] '%s' @ '%s'\n",
                         return_value8_1, return_value8_2, total, current->pattern, current->input);
                     is_successful = 0;
-                } else if (return_value8_1 >= 0) {
-                    return_value8_1 *= 2;
+                } else if (return_value8_1 >= 0 || return_value8_1 == PCRE_ERROR_PARTIAL) {
+                    if (return_value8_1 == PCRE_ERROR_PARTIAL)
+                        return_value8_1 = 2;
+                    else
+                        return_value8_1 *= 2;
+
                     for (i = 0; i < return_value8_1; ++i)
                         if (ovector8_1[i] != ovector8_2[i]) {
                             printf("\n8 bit: Ovector[%d] value differs(%d:%d): [%d] '%s' @ '%s'\n",
@@ -1090,8 +1120,12 @@
                     printf("\n16 bit: Return value differs(%d:%d): [%d] '%s' @ '%s'\n",
                         return_value16_1, return_value16_2, total, current->pattern, current->input);
                     is_successful = 0;
-                } else if (return_value16_1 >= 0) {
-                    return_value16_1 *= 2;
+                } else if (return_value16_1 >= 0 || return_value16_1 == PCRE_ERROR_PARTIAL) {
+                    if (return_value16_1 == PCRE_ERROR_PARTIAL)
+                        return_value16_1 = 2;
+                    else
+                        return_value16_1 *= 2;
+
                     for (i = 0; i < return_value16_1; ++i)
                         if (ovector16_1[i] != ovector16_2[i]) {
                             printf("\n16 bit: Ovector[%d] value differs(%d:%d): [%d] '%s' @ '%s'\n",
@@ -1155,7 +1189,6 @@
         }
 #endif


-        /* printf("[%d-%d|%d-%d]%s", ovector8_1[0], ovector8_1[1], ovector16_1[0], ovector16_1[1], (current->flags & PCRE_CASELESS) ? "C" : ""); */
         printf(".");
         fflush(stdout);
         current++;


Modified: code/trunk/pcre_study.c
===================================================================
--- code/trunk/pcre_study.c    2012-02-12 17:06:59 UTC (rev 913)
+++ code/trunk/pcre_study.c    2012-02-13 06:04:50 UTC (rev 914)
@@ -1418,7 +1418,8 @@


 if (bits_set || min > 0
 #ifdef SUPPORT_JIT
-    || (options & PCRE_STUDY_JIT_COMPILE) != 0
+    || (options & (PCRE_STUDY_JIT_COMPILE | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE
+                 | PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE)) != 0
 #endif
   )
   {
@@ -1478,7 +1479,13 @@


 #ifdef SUPPORT_JIT
   extra->executable_jit = NULL;
-  if ((options & PCRE_STUDY_JIT_COMPILE) != 0) PRIV(jit_compile)(re, extra);
+  if ((options & PCRE_STUDY_JIT_COMPILE) != 0)
+    PRIV(jit_compile)(re, extra, JIT_COMPILE);
+  if ((options & PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE) != 0)
+    PRIV(jit_compile)(re, extra, JIT_PARTIAL_SOFT_COMPILE);
+  if ((options & PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE) != 0)
+    PRIV(jit_compile)(re, extra, JIT_PARTIAL_HARD_COMPILE);
+
   if (study->flags == 0 && (extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) == 0)
     {
 #ifdef COMPILE_PCRE8


Modified: code/trunk/pcretest.c
===================================================================
--- code/trunk/pcretest.c    2012-02-12 17:06:59 UTC (rev 913)
+++ code/trunk/pcretest.c    2012-02-13 06:04:50 UTC (rev 914)
@@ -2239,7 +2239,9 @@
   else if (strcmp(argv[op], "-s+") == 0)
     {
     force_study = 1;
-    force_study_options = PCRE_STUDY_JIT_COMPILE;
+    force_study_options = PCRE_STUDY_JIT_COMPILE
+                        | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE
+                        | PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE;
     }
   else if (strcmp(argv[op], "-16") == 0)
     {
@@ -2768,7 +2770,9 @@
         do_study = 1;
         if (*pp == '+')
           {
-          study_options |= PCRE_STUDY_JIT_COMPILE;
+          study_options |= PCRE_STUDY_JIT_COMPILE
+                        | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE
+                        | PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE;
           pp++;
           }
         }