diff --git a/ChangeLog.txt b/ChangeLog.txt index 1056279ac6..e81dc228e3 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,10 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2014-02-03 09:09 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * src/3rd/pcre/* + * updated PCRE 8.31 -> 8.34 + 2014-02-02 19:22 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * contrib/3rd/sqlite3/* * sqlite3 update 3.7.16.2. -> 3.8.2 diff --git a/src/3rd/pcre/LICENCE b/src/3rd/pcre/LICENCE index 5ce31a828d..3aff6a62c0 100644 --- a/src/3rd/pcre/LICENCE +++ b/src/3rd/pcre/LICENCE @@ -24,7 +24,7 @@ Email domain: cam.ac.uk University of Cambridge Computing Service, Cambridge, England. -Copyright (c) 1997-2012 University of Cambridge +Copyright (c) 1997-2013 University of Cambridge All rights reserved. @@ -35,7 +35,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Emain domain: freemail.hu -Copyright(c) 2010-2012 Zoltan Herczeg +Copyright(c) 2010-2013 Zoltan Herczeg All rights reserved. @@ -46,7 +46,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Emain domain: freemail.hu -Copyright(c) 2009-2012 Zoltan Herczeg +Copyright(c) 2009-2013 Zoltan Herczeg All rights reserved. diff --git a/src/3rd/pcre/Makefile b/src/3rd/pcre/Makefile index 97b1bcd0fa..6ee3002d43 100644 --- a/src/3rd/pcre/Makefile +++ b/src/3rd/pcre/Makefile @@ -31,17 +31,18 @@ LIBNAME := hbpcre ifneq ($(HB_HAS_PCRE_LOCAL),) - HB_CFLAGS += -DHAVE_STDINT_H=0 HB_CFLAGS += -DSUPPORT_UTF -DSUPPORT_UCP # only needed for win/wce, for other platforms this is noop HB_CFLAGS_STA := -DPCRE_STATIC - ifneq ($(filter $(HB_COMPILER),bcc msvc msvc64 msvcia64 msvcarm icc iccia64 djgpp),) - HB_CFLAGS += -DHAVE_INTTYPES_H=0 + ifeq ($(filter $(HB_PLATFORM),win wince dos vxworks),) + HB_CFLAGS += -DHAVE_STDINT_H else - ifneq ($(filter $(HB_PLATFORM),vxworks),) - HB_CFLAGS += -DHAVE_INTTYPES_H=0 - endif + ifeq ($(filter $(HB_COMPILER),bcc msvc msvc64 msvcia64 msvcarm icc iccia64 djgpp),) + ifeq ($(filter $(HB_PLATFORM),vxworks),) + HB_CFLAGS += -DHAVE_STDINT_H + endif + endif endif # ifneq ($(filter $(HB_COMPILER),mingw mingw64 msvc mvc64)$(filter $(HB_PLATFORM),darwin linux),) @@ -73,8 +74,8 @@ else endif # ORIGIN http://www.pcre.org/ -# VER 8.31 -# URL ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.31.tar.gz +# VER 8.34 +# URL ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.34.tar.gz # DIFF pcre.dif # # MAP LICENCE diff --git a/src/3rd/pcre/chartabs.c b/src/3rd/pcre/chartabs.c index 57a6c311a6..2600f9267e 100644 --- a/src/3rd/pcre/chartabs.c +++ b/src/3rd/pcre/chartabs.c @@ -163,7 +163,7 @@ graph, print, punct, and cntrl. Other classes are built from combinations. */ */ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ - 0x00,0x01,0x01,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */ + 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */ diff --git a/src/3rd/pcre/config.h b/src/3rd/pcre/config.h index b5be736eac..58fb5a214f 100644 --- a/src/3rd/pcre/config.h +++ b/src/3rd/pcre/config.h @@ -1,62 +1,70 @@ /* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ +/* PCRE is written in Standard C, but there are a few non-standard things it +can cope with, allowing it to run on SunOS4 and other "close to standard" +systems. -/* On Unix-like systems config.h.in is converted by "configure" into config.h. -Some other environments also support the use of "configure". PCRE is written in -Standard C, but there are a few non-standard things it can cope with, allowing -it to run on SunOS4 and other "close to standard" systems. - -If you are going to build PCRE "by hand" on a system without "configure" you -should copy the distributed config.h.generic to config.h, and then set up the -macro definitions the way you need them. You must then add -DHAVE_CONFIG_H to -all of your compile commands, so that config.h is included at the start of -every source. +In environments that support the GNU autotools, config.h.in is converted into +config.h by the "configure" script. In environments that use CMake, +config-cmake.in is converted into config.h. If you are going to build PCRE "by +hand" without using "configure" or CMake, you should copy the distributed +config.h.generic to config.h, and edit the macro definitions to be the way you +need them. You must then add -DHAVE_CONFIG_H to all of your compile commands, +so that config.h is included at the start of every source. Alternatively, you can avoid editing by using -D on the compiler command line -to set the macro values. In this case, you do not have to set -DHAVE_CONFIG_H. +to set the macro values. In this case, you do not have to set -DHAVE_CONFIG_H, +but if you do, default values will be taken from config.h for non-boolean +macros that are not defined on the command line. -PCRE uses memmove() if HAVE_MEMMOVE is set to 1; otherwise it uses bcopy() if -HAVE_BCOPY is set to 1. If your system has neither bcopy() nor memmove(), set -them both to 0; an emulation function will be used. */ +Boolean macros such as HAVE_STDLIB_H and SUPPORT_PCRE8 should either be defined +(conventionally to 1) for TRUE, and not defined at all for FALSE. All such +macros are listed as a commented #undef in config.h.generic. Macros such as +MATCH_LIMIT, whose actual value is relevant, have defaults defined, but are +surrounded by #ifndef/#endif lines so that the value can be overridden by -D. + +PCRE uses memmove() if HAVE_MEMMOVE is defined; otherwise it uses bcopy() if +HAVE_BCOPY is defined. If your system has neither bcopy() nor memmove(), make +sure both macros are undefined; an emulation function will then be used. */ /* By default, the \R escape sequence matches any Unicode line ending - character or sequence of characters. If BSR_ANYCRLF is defined, this is - changed so that backslash-R matches only CR, LF, or CRLF. The build- time - default can be overridden by the user of PCRE at runtime. On systems that - support it, "configure" can be used to override the default. */ + character or sequence of characters. If BSR_ANYCRLF is defined (to any + value), this is changed so that backslash-R matches only CR, LF, or CRLF. + The build-time default can be overridden by the user of PCRE at runtime. */ /* #undef BSR_ANYCRLF */ /* If you are compiling for a system that uses EBCDIC instead of ASCII - character codes, define this macro as 1. On systems that can use - "configure", this can be done via --enable-ebcdic. PCRE will then assume - that all input strings are in EBCDIC. If you do not define this macro, PCRE - will assume input strings are ASCII or UTF-8/16 Unicode. It is not possible - to build a version of PCRE that supports both EBCDIC and UTF-8/16. */ + character codes, define this macro to any value. You must also edit the + NEWLINE macro below to set a suitable EBCDIC newline, commonly 21 (0x15). + On systems that can use "configure" or CMake to set EBCDIC, NEWLINE is + automatically adjusted. When EBCDIC is set, PCRE assumes that all input + strings are in EBCDIC. If you do not define this macro, PCRE will assume + input strings are ASCII or UTF-8/16/32 Unicode. It is not possible to build + a version of PCRE that supports both EBCDIC and UTF-8/16/32. */ /* #undef EBCDIC */ +/* In an EBCDIC environment, define this macro to any value to arrange for the + NL character to be 0x25 instead of the default 0x15. NL plays the role that + LF does in an ASCII/Unicode environment. The value must also be set in the + NEWLINE macro below. On systems that can use "configure" or CMake to set + EBCDIC_NL25, the adjustment of NEWLINE is automatic. */ +/* #undef EBCDIC_NL25 */ + /* Define to 1 if you have the `bcopy' function. */ -#ifndef HAVE_BCOPY -#define HAVE_BCOPY 1 -#endif +/* #undef HAVE_BCOPY */ /* Define to 1 if you have the header file. */ /* #undef HAVE_BITS_TYPE_TRAITS_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_BZLIB_H -#define HAVE_BZLIB_H 1 -#endif +/* #undef HAVE_BZLIB_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_DIRENT_H -#define HAVE_DIRENT_H 1 -#endif +/* #undef HAVE_DIRENT_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_DLFCN_H -#define HAVE_DLFCN_H 1 -#endif +/* #undef HAVE_DLFCN_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_EDITLINE_READLINE_H */ @@ -65,29 +73,25 @@ them both to 0; an emulation function will be used. */ /* #undef HAVE_EDIT_READLINE_READLINE_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_INTTYPES_H -#define HAVE_INTTYPES_H 1 -#endif +/* #undef HAVE_INTTYPES_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_LIMITS_H -#define HAVE_LIMITS_H 1 -#endif +/* #undef HAVE_LIMITS_H */ /* Define to 1 if the system has the type `long long'. */ -#ifndef HAVE_LONG_LONG -#define HAVE_LONG_LONG 1 -#endif +/* #undef HAVE_LONG_LONG */ /* Define to 1 if you have the `memmove' function. */ -#ifndef HAVE_MEMMOVE -#define HAVE_MEMMOVE 1 -#endif +/* #undef HAVE_MEMMOVE */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_MEMORY_H -#define HAVE_MEMORY_H 1 -#endif +/* #undef HAVE_MEMORY_H */ + +/* Define if you have POSIX threads libraries and header files. */ +/* #undef HAVE_PTHREAD */ + +/* Have PTHREAD_PRIO_INHERIT. */ +/* #undef HAVE_PTHREAD_PRIO_INHERIT */ /* Define to 1 if you have the header file. */ /* #undef HAVE_READLINE_HISTORY_H */ @@ -96,34 +100,22 @@ them both to 0; an emulation function will be used. */ /* #undef HAVE_READLINE_READLINE_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_STDINT_H -#define HAVE_STDINT_H 1 -#endif +/* #undef HAVE_STDINT_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_STDLIB_H -#define HAVE_STDLIB_H 1 -#endif +/* #undef HAVE_STDLIB_H */ /* Define to 1 if you have the `strerror' function. */ -#ifndef HAVE_STRERROR -#define HAVE_STRERROR 1 -#endif +/* #undef HAVE_STRERROR */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_STRING -#define HAVE_STRING 1 -#endif +/* #undef HAVE_STRING */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_STRINGS_H -#define HAVE_STRINGS_H 1 -#endif +/* #undef HAVE_STRINGS_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_STRING_H -#define HAVE_STRING_H 1 -#endif +/* #undef HAVE_STRING_H */ /* Define to 1 if you have `strtoimax'. */ /* #undef HAVE_STRTOIMAX */ @@ -132,40 +124,31 @@ them both to 0; an emulation function will be used. */ /* #undef HAVE_STRTOLL */ /* Define to 1 if you have `strtoq'. */ -#ifndef HAVE_STRTOQ -#define HAVE_STRTOQ 1 -#endif +/* #undef HAVE_STRTOQ */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_SYS_STAT_H -#define HAVE_SYS_STAT_H 1 -#endif +/* #undef HAVE_SYS_STAT_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_SYS_TYPES_H -#define HAVE_SYS_TYPES_H 1 -#endif +/* #undef HAVE_SYS_TYPES_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_TYPE_TRAITS_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_UNISTD_H -#define HAVE_UNISTD_H 1 -#endif +/* #undef HAVE_UNISTD_H */ /* Define to 1 if the system has the type `unsigned long long'. */ -#ifndef HAVE_UNSIGNED_LONG_LONG -#define HAVE_UNSIGNED_LONG_LONG 1 -#endif +/* #undef HAVE_UNSIGNED_LONG_LONG */ + +/* Define to 1 if the compiler supports simple visibility declarations. */ +/* #undef HAVE_VISIBILITY */ /* Define to 1 if you have the header file. */ /* #undef HAVE_WINDOWS_H */ /* Define to 1 if you have the header file. */ -#ifndef HAVE_ZLIB_H -#define HAVE_ZLIB_H 1 -#endif +/* #undef HAVE_ZLIB_H */ /* Define to 1 if you have `_strtoi64'. */ /* #undef HAVE__STRTOI64 */ @@ -174,14 +157,14 @@ them both to 0; an emulation function will be used. */ as offsets within the compiled regex. The default is 2, which allows for compiled patterns up to 64K long. This covers the vast majority of cases. However, PCRE can also be compiled to use 3 or 4 bytes instead. This allows - for longer patterns in extreme cases. On systems that support it, - "configure" can be used to override this default. */ + for longer patterns in extreme cases. */ #ifndef LINK_SIZE #define LINK_SIZE 2 #endif /* Define to the sub-directory in which libtool stores uninstalled libraries. */ +/* This is ignored unless you are using libtool. */ #ifndef LT_OBJDIR #define LT_OBJDIR ".libs/" #endif @@ -191,8 +174,7 @@ them both to 0; an emulation function will be used. */ pcre_exec(). There is a runtime interface for setting a different limit. The limit exists in order to catch runaway regular expressions that take for ever to determine that they do not match. The default is set very large - so that it does not accidentally catch legitimate cases. On systems that - support it, "configure" can be used to override this default default. */ + so that it does not accidentally catch legitimate cases. */ #ifndef MATCH_LIMIT #define MATCH_LIMIT 10000000 #endif @@ -204,8 +186,7 @@ them both to 0; an emulation function will be used. */ used. The value of MATCH_LIMIT_RECURSION applies only to recursive calls of match(). To have any useful effect, it must be less than the value of MATCH_LIMIT. The default is to use the same value as MATCH_LIMIT. There is - a runtime method for setting a different limit. On systems that support it, - "configure" can be used to override the default. */ + a runtime method for setting a different limit. */ #ifndef MATCH_LIMIT_RECURSION #define MATCH_LIMIT_RECURSION MATCH_LIMIT #endif @@ -224,22 +205,25 @@ them both to 0; an emulation function will be used. */ #define MAX_NAME_SIZE 32 #endif -/* The value of NEWLINE determines the newline character sequence. On systems - that support it, "configure" can be used to override the default, which is - 10. The possible values are 10 (LF), 13 (CR), 3338 (CRLF), -1 (ANY), or -2 - (ANYCRLF). */ +/* The value of NEWLINE determines the default newline character sequence. + PCRE client programs can override this by selecting other values at run + time. In ASCII environments, the value can be 10 (LF), 13 (CR), or 3338 + (CRLF); in EBCDIC environments the value can be 21 or 37 (LF), 13 (CR), or + 3349 or 3365 (CRLF) because there are two alternative codepoints (0x15 and + 0x25) that are used as the NL line terminator that is equivalent to ASCII + LF. In both ASCII and EBCDIC environments the value can also be -1 (ANY), + or -2 (ANYCRLF). */ #ifndef NEWLINE #define NEWLINE 10 #endif /* PCRE uses recursive function calls to handle backtracking while matching. This can sometimes be a problem on systems that have stacks of limited - size. Define NO_RECURSE to get a version that doesn't use recursion in the - match() function; instead it creates its own stack by steam using - pcre_recurse_malloc() to obtain memory from the heap. For more detail, see - the comments and other stuff just above the match() function. On systems - that support it, "configure" can be used to set this in the Makefile (use - --disable-stack-for-recursion). */ + size. Define NO_RECURSE to any value to get a version that doesn't use + recursion in the match() function; instead it creates its own stack by + steam using pcre_recurse_malloc() to obtain memory from the heap. For more + detail, see the comments and other stuff just above the match() function. + */ /* #undef NO_RECURSE */ /* Name of package */ @@ -252,7 +236,7 @@ them both to 0; an emulation function will be used. */ #define PACKAGE_NAME "PCRE" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PCRE 8.31" +#define PACKAGE_STRING "PCRE 8.34" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "pcre" @@ -261,31 +245,36 @@ them both to 0; an emulation function will be used. */ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "8.31" +#define PACKAGE_VERSION "8.34" + +/* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested + parentheses (of any kind) in a pattern. This limits the amount of system + stack that is used while compiling a pattern. */ +#ifndef PARENS_NEST_LIMIT +#define PARENS_NEST_LIMIT 250 +#endif /* The value of PCREGREP_BUFSIZE determines the size of buffer used by - pcregrep to hold parts of the file it is searching. On systems that support - it, "configure" can be used to override the default, which is 8192. This is - also the minimum value. The actual amount of memory used by pcregrep is - three times this number, because it allows for the buffering of "before" - and "after" lines. */ + pcregrep to hold parts of the file it is searching. This is also the + minimum value. The actual amount of memory used by pcregrep is three times + this number, because it allows for the buffering of "before" and "after" + lines. */ #ifndef PCREGREP_BUFSIZE #define PCREGREP_BUFSIZE 20480 #endif - /* If you are compiling for a system other than a Unix-like system or Win32, and it needs some magic to be inserted before the definition of a function that is exported by the library, define this macro to - contain the relevant magic. If you do not define this macro, it - defaults to "extern" for a C compiler and "extern C" for a C++ - compiler on non-Win32 systems. This macro apears at the start of - every exported function that is part of the external API. It does - not appear on functions that are "external" in the C sense, but - which are internal to the library. */ + contain the relevant magic. If you do not define this macro, a suitable + __declspec value is used for Windows systems; in other environments + "extern" is used for a C compiler and "extern C" for a C++ compiler. + This macro apears at the start of every exported function that is part + of the external API. It does not appear on functions that are "external" + in the C sense, but which are internal to the library. */ /* #undef PCRE_EXP_DEFN */ -/* Define if linking statically (TODO: make nice with Libtool) */ +/* Define to any value if linking statically (TODO: make nice with Libtool) */ /* #undef PCRE_STATIC */ /* When calling PCRE via the POSIX interface, additional working storage is @@ -294,58 +283,61 @@ them both to 0; an emulation function will be used. */ only two. If the number of expected substrings is small, the wrapper function uses space on the stack, because this is faster than using malloc() for each call. The threshold above which the stack is no longer - used is defined by POSIX_MALLOC_THRESHOLD. On systems that support it, - "configure" can be used to override this default. */ + used is defined by POSIX_MALLOC_THRESHOLD. */ #ifndef POSIX_MALLOC_THRESHOLD #define POSIX_MALLOC_THRESHOLD 10 #endif -/* Define to 1 if you have the ANSI C header files. */ -#ifndef STDC_HEADERS -#define STDC_HEADERS 1 -#endif +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ -/* Define to enable support for Just-In-Time compiling. */ +/* Define to 1 if you have the ANSI C header files. */ +/* #undef STDC_HEADERS */ + +/* Define to any value to enable support for Just-In-Time compiling. */ /* #undef SUPPORT_JIT */ -/* Define to allow pcregrep to be linked with libbz2, so that it is able to - handle .bz2 files. */ +/* Define to any value to allow pcregrep to be linked with libbz2, so that it + is able to handle .bz2 files. */ /* #undef SUPPORT_LIBBZ2 */ -/* Define to allow pcretest to be linked with libedit. */ +/* Define to any value to allow pcretest to be linked with libedit. */ /* #undef SUPPORT_LIBEDIT */ -/* Define to allow pcretest to be linked with libreadline. */ +/* Define to any value to allow pcretest to be linked with libreadline. */ /* #undef SUPPORT_LIBREADLINE */ -/* Define to allow pcregrep to be linked with libz, so that it is able to - handle .gz files. */ +/* Define to any value to allow pcregrep to be linked with libz, so that it is + able to handle .gz files. */ /* #undef SUPPORT_LIBZ */ -/* Define to enable the 16 bit PCRE library. */ +/* Define to any value to enable the 16 bit PCRE library. */ /* #undef SUPPORT_PCRE16 */ -/* Define to enable the 8 bit PCRE library. */ -#ifndef SUPPORT_PCRE8 -#define SUPPORT_PCRE8 /**/ -#endif +/* Define to any value to enable the 32 bit PCRE library. */ +/* #undef SUPPORT_PCRE32 */ -/* Define to enable JIT support in pcregrep. */ +/* Define to any value to enable the 8 bit PCRE library. */ +/* #undef SUPPORT_PCRE8 */ + +/* Define to any value to enable JIT support in pcregrep. */ /* #undef SUPPORT_PCREGREP_JIT */ -/* Define to enable support for Unicode properties. */ +/* Define to any value to enable support for Unicode properties. */ /* #undef SUPPORT_UCP */ -/* Define to enable support for the UTF-8/16 Unicode encoding. This will work - even in an EBCDIC environment, but it is incompatible with the EBCDIC - macro. That is, PCRE can support *either* EBCDIC code *or* ASCII/UTF-8/16, - but not both at once. */ +/* Define to any value to enable support for the UTF-8/16/32 Unicode encoding. + This will work even in an EBCDIC environment, but it is incompatible with + the EBCDIC macro. That is, PCRE can support *either* EBCDIC code *or* + ASCII/UTF-8/16/32, but not both at once. */ /* #undef SUPPORT_UTF */ +/* Define to any value for valgrind support to find invalid memory reads. */ +/* #undef SUPPORT_VALGRIND */ + /* Version number of package */ -#ifndef VERSION -#define VERSION "8.31" -#endif +#define VERSION "8.34" /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ diff --git a/src/3rd/pcre/pcre.dif b/src/3rd/pcre/pcre.dif index d74f3b6462..8cfaf9aee3 100644 --- a/src/3rd/pcre/pcre.dif +++ b/src/3rd/pcre/pcre.dif @@ -1,6 +1,6 @@ diff -urN pcre.orig/pcrejitc.c pcre/pcrejitc.c ---- pcre.orig/pcrejitc.c Wed Jul 11 12:26:04 2012 -+++ pcre/pcrejitc.c Wed Jul 11 12:26:05 2012 +--- pcre.orig/pcrejitc.c 2014-02-03 09:05:44.496039042 +0100 ++++ pcre/pcrejitc.c 2014-02-03 09:05:44.496039042 +0100 @@ -59,7 +59,7 @@ #define SLJIT_VERBOSE 0 #define SLJIT_DEBUG 0 @@ -11,11 +11,11 @@ diff -urN pcre.orig/pcrejitc.c pcre/pcrejitc.c #if defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED #error Unsupported architecture diff -urN pcre.orig/sjconfi.h pcre/sjconfi.h ---- pcre.orig/sjconfi.h Wed Jul 11 12:26:04 2012 -+++ pcre/sjconfi.h Wed Jul 11 12:26:05 2012 -@@ -282,8 +282,12 @@ +--- pcre.orig/sjconfi.h 2014-02-03 09:05:44.536039042 +0100 ++++ pcre/sjconfi.h 2014-02-03 09:05:44.536039042 +0100 +@@ -323,8 +323,12 @@ - #if defined(__GNUC__) + #if defined(__GNUC__) && !defined(__APPLE__) +#if ( __GNUC__ > 3 ) || ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 4 ) ) #define SLJIT_CALL __attribute__ ((fastcall)) @@ -24,5 +24,5 @@ diff -urN pcre.orig/sjconfi.h pcre/sjconfi.h +#define SLJIT_CALL +#endif - #elif defined(_WIN32) + #elif defined(_MSC_VER) diff --git a/src/3rd/pcre/pcre.h b/src/3rd/pcre/pcre.h index b71ead37a8..c85f36b6bc 100644 --- a/src/3rd/pcre/pcre.h +++ b/src/3rd/pcre/pcre.h @@ -5,7 +5,7 @@ /* This is the public header file for the PCRE library, to be #included by applications that call the PCRE functions. - Copyright (c) 1997-2012 University of Cambridge + Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE. /* The current PCRE version information. */ #define PCRE_MAJOR 8 -#define PCRE_MINOR 31 +#define PCRE_MINOR 34 #define PCRE_PRERELEASE -#define PCRE_DATE 2012-07-06 +#define PCRE_DATE 2013-12-15 /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE, the appropriate @@ -95,54 +95,80 @@ it is needed here for malloc. */ extern "C" { #endif -/* Options. Some are compile-time only, some are run-time only, and some are -both, so we keep them all distinct. However, almost all the bits in the options -word are now used. In the long run, we may have to re-use some of the -compile-time only bits for runtime options, or vice versa. In the comments -below, "compile", "exec", and "DFA exec" mean that the option is permitted to -be set for those functions; "used in" means that an option may be set only for -compile, but is subsequently referenced in exec and/or DFA exec. Any of the -compile-time options may be inspected during studying (and therefore JIT -compiling). */ +/* Public options. Some are compile-time only, some are run-time only, and some +are both. Most of the compile-time options are saved with the compiled regex so +that they can be inspected during studying (and therefore JIT compiling). Note +that pcre_study() has its own set of options. Originally, all the options +defined here used distinct bits. However, almost all the bits in a 32-bit word +are now used, so in order to conserve them, option bits that were previously +only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may +also be used for compile-time options that affect only compiling and are not +relevant for studying or JIT compiling. -#define PCRE_CASELESS 0x00000001 /* Compile */ -#define PCRE_MULTILINE 0x00000002 /* Compile */ -#define PCRE_DOTALL 0x00000004 /* Compile */ -#define PCRE_EXTENDED 0x00000008 /* Compile */ -#define PCRE_ANCHORED 0x00000010 /* Compile, exec, DFA exec */ -#define PCRE_DOLLAR_ENDONLY 0x00000020 /* Compile, used in exec, DFA exec */ -#define PCRE_EXTRA 0x00000040 /* Compile */ -#define PCRE_NOTBOL 0x00000080 /* Exec, DFA exec */ -#define PCRE_NOTEOL 0x00000100 /* Exec, DFA exec */ -#define PCRE_UNGREEDY 0x00000200 /* Compile */ -#define PCRE_NOTEMPTY 0x00000400 /* Exec, DFA exec */ -/* The next two are also used in exec and DFA exec */ -#define PCRE_UTF8 0x00000800 /* Compile (same as PCRE_UTF16) */ -#define PCRE_UTF16 0x00000800 /* Compile (same as PCRE_UTF8) */ -#define PCRE_NO_AUTO_CAPTURE 0x00001000 /* Compile */ -/* The next two are also used in exec and DFA exec */ -#define PCRE_NO_UTF8_CHECK 0x00002000 /* Compile (same as PCRE_NO_UTF16_CHECK) */ -#define PCRE_NO_UTF16_CHECK 0x00002000 /* Compile (same as PCRE_NO_UTF8_CHECK) */ -#define PCRE_AUTO_CALLOUT 0x00004000 /* Compile */ -#define PCRE_PARTIAL_SOFT 0x00008000 /* Exec, DFA exec */ -#define PCRE_PARTIAL 0x00008000 /* Backwards compatible synonym */ -#define PCRE_DFA_SHORTEST 0x00010000 /* DFA exec */ -#define PCRE_DFA_RESTART 0x00020000 /* DFA exec */ -#define PCRE_FIRSTLINE 0x00040000 /* Compile, used in exec, DFA exec */ -#define PCRE_DUPNAMES 0x00080000 /* Compile */ -#define PCRE_NEWLINE_CR 0x00100000 /* Compile, exec, DFA exec */ -#define PCRE_NEWLINE_LF 0x00200000 /* Compile, exec, DFA exec */ -#define PCRE_NEWLINE_CRLF 0x00300000 /* Compile, exec, DFA exec */ -#define PCRE_NEWLINE_ANY 0x00400000 /* Compile, exec, DFA exec */ -#define PCRE_NEWLINE_ANYCRLF 0x00500000 /* Compile, exec, DFA exec */ -#define PCRE_BSR_ANYCRLF 0x00800000 /* Compile, exec, DFA exec */ -#define PCRE_BSR_UNICODE 0x01000000 /* Compile, exec, DFA exec */ -#define PCRE_JAVASCRIPT_COMPAT 0x02000000 /* Compile, used in exec */ -#define PCRE_NO_START_OPTIMIZE 0x04000000 /* Compile, exec, DFA exec */ -#define PCRE_NO_START_OPTIMISE 0x04000000 /* Synonym */ -#define PCRE_PARTIAL_HARD 0x08000000 /* Exec, DFA exec */ -#define PCRE_NOTEMPTY_ATSTART 0x10000000 /* Exec, DFA exec */ -#define PCRE_UCP 0x20000000 /* Compile, used in exec, DFA exec */ +Some options for pcre_compile() change its behaviour but do not affect the +behaviour of the execution functions. Other options are passed through to the +execution functions and affect their behaviour, with or without affecting the +behaviour of pcre_compile(). + +Options that can be passed to pcre_compile() are tagged Cx below, with these +variants: + +C1 Affects compile only +C2 Does not affect compile; affects exec, dfa_exec +C3 Affects compile, exec, dfa_exec +C4 Affects compile, exec, dfa_exec, study +C5 Affects compile, exec, study + +Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged with +E and D, respectively. They take precedence over C3, C4, and C5 settings passed +from pcre_compile(). Those that are compatible with JIT execution are flagged +with J. */ + +#define PCRE_CASELESS 0x00000001 /* C1 */ +#define PCRE_MULTILINE 0x00000002 /* C1 */ +#define PCRE_DOTALL 0x00000004 /* C1 */ +#define PCRE_EXTENDED 0x00000008 /* C1 */ +#define PCRE_ANCHORED 0x00000010 /* C4 E D */ +#define PCRE_DOLLAR_ENDONLY 0x00000020 /* C2 */ +#define PCRE_EXTRA 0x00000040 /* C1 */ +#define PCRE_NOTBOL 0x00000080 /* E D J */ +#define PCRE_NOTEOL 0x00000100 /* E D J */ +#define PCRE_UNGREEDY 0x00000200 /* C1 */ +#define PCRE_NOTEMPTY 0x00000400 /* E D J */ +#define PCRE_UTF8 0x00000800 /* C4 ) */ +#define PCRE_UTF16 0x00000800 /* C4 ) Synonyms */ +#define PCRE_UTF32 0x00000800 /* C4 ) */ +#define PCRE_NO_AUTO_CAPTURE 0x00001000 /* C1 */ +#define PCRE_NO_UTF8_CHECK 0x00002000 /* C1 E D J ) */ +#define PCRE_NO_UTF16_CHECK 0x00002000 /* C1 E D J ) Synonyms */ +#define PCRE_NO_UTF32_CHECK 0x00002000 /* C1 E D J ) */ +#define PCRE_AUTO_CALLOUT 0x00004000 /* C1 */ +#define PCRE_PARTIAL_SOFT 0x00008000 /* E D J ) Synonyms */ +#define PCRE_PARTIAL 0x00008000 /* E D J ) */ + +/* This pair use the same bit. */ +#define PCRE_NEVER_UTF 0x00010000 /* C1 ) Overlaid */ +#define PCRE_DFA_SHORTEST 0x00010000 /* D ) Overlaid */ + +/* This pair use the same bit. */ +#define PCRE_NO_AUTO_POSSESS 0x00020000 /* C1 ) Overlaid */ +#define PCRE_DFA_RESTART 0x00020000 /* D ) Overlaid */ + +#define PCRE_FIRSTLINE 0x00040000 /* C3 */ +#define PCRE_DUPNAMES 0x00080000 /* C1 */ +#define PCRE_NEWLINE_CR 0x00100000 /* C3 E D */ +#define PCRE_NEWLINE_LF 0x00200000 /* C3 E D */ +#define PCRE_NEWLINE_CRLF 0x00300000 /* C3 E D */ +#define PCRE_NEWLINE_ANY 0x00400000 /* C3 E D */ +#define PCRE_NEWLINE_ANYCRLF 0x00500000 /* C3 E D */ +#define PCRE_BSR_ANYCRLF 0x00800000 /* C3 E D */ +#define PCRE_BSR_UNICODE 0x01000000 /* C3 E D */ +#define PCRE_JAVASCRIPT_COMPAT 0x02000000 /* C5 */ +#define PCRE_NO_START_OPTIMIZE 0x04000000 /* C2 E D ) Synonyms */ +#define PCRE_NO_START_OPTIMISE 0x04000000 /* C2 E D ) */ +#define PCRE_PARTIAL_HARD 0x08000000 /* E D J */ +#define PCRE_NOTEMPTY_ATSTART 0x10000000 /* E D J */ +#define PCRE_UCP 0x20000000 /* C3 */ /* Exec-time and get/set-time error codes */ @@ -156,8 +182,9 @@ compiling). */ #define PCRE_ERROR_NOSUBSTRING (-7) #define PCRE_ERROR_MATCHLIMIT (-8) #define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ -#define PCRE_ERROR_BADUTF8 (-10) /* Same for 8/16 */ -#define PCRE_ERROR_BADUTF16 (-10) /* Same for 8/16 */ +#define PCRE_ERROR_BADUTF8 (-10) /* Same for 8/16/32 */ +#define PCRE_ERROR_BADUTF16 (-10) /* Same for 8/16/32 */ +#define PCRE_ERROR_BADUTF32 (-10) /* Same for 8/16/32 */ #define PCRE_ERROR_BADUTF8_OFFSET (-11) /* Same for 8/16 */ #define PCRE_ERROR_BADUTF16_OFFSET (-11) /* Same for 8/16 */ #define PCRE_ERROR_PARTIAL (-12) @@ -180,6 +207,9 @@ compiling). */ #define PCRE_ERROR_BADMODE (-28) #define PCRE_ERROR_BADENDIANNESS (-29) #define PCRE_ERROR_DFA_BADRESTART (-30) +#define PCRE_ERROR_JIT_BADOPTION (-31) +#define PCRE_ERROR_BADLENGTH (-32) +#define PCRE_ERROR_UNSET (-33) /* Specific error codes for UTF-8 validity checks */ @@ -205,6 +235,7 @@ compiling). */ #define PCRE_UTF8_ERR19 19 #define PCRE_UTF8_ERR20 20 #define PCRE_UTF8_ERR21 21 +#define PCRE_UTF8_ERR22 22 /* Unused (was non-character) */ /* Specific error codes for UTF-16 validity checks */ @@ -212,7 +243,14 @@ compiling). */ #define PCRE_UTF16_ERR1 1 #define PCRE_UTF16_ERR2 2 #define PCRE_UTF16_ERR3 3 -#define PCRE_UTF16_ERR4 4 +#define PCRE_UTF16_ERR4 4 /* Unused (was non-character) */ + +/* Specific error codes for UTF-32 validity checks */ + +#define PCRE_UTF32_ERR0 0 +#define PCRE_UTF32_ERR1 1 +#define PCRE_UTF32_ERR2 2 /* Unused (was non-character) */ +#define PCRE_UTF32_ERR3 3 /* Request types for pcre_fullinfo() */ @@ -236,6 +274,13 @@ compiling). */ #define PCRE_INFO_JIT 16 #define PCRE_INFO_JITSIZE 17 #define PCRE_INFO_MAXLOOKBEHIND 18 +#define PCRE_INFO_FIRSTCHARACTER 19 +#define PCRE_INFO_FIRSTCHARACTERFLAGS 20 +#define PCRE_INFO_REQUIREDCHAR 21 +#define PCRE_INFO_REQUIREDCHARFLAGS 22 +#define PCRE_INFO_MATCHLIMIT 23 +#define PCRE_INFO_RECURSIONLIMIT 24 +#define PCRE_INFO_MATCH_EMPTY 25 /* Request types for pcre_config(). Do not re-arrange, in order to remain compatible. */ @@ -252,6 +297,8 @@ compatible. */ #define PCRE_CONFIG_JIT 9 #define PCRE_CONFIG_UTF16 10 #define PCRE_CONFIG_JITTARGET 11 +#define PCRE_CONFIG_UTF32 12 +#define PCRE_CONFIG_PARENS_LIMIT 13 /* Request types for pcre_study(). Do not re-arrange, in order to remain compatible. */ @@ -259,8 +306,9 @@ compatible. */ #define PCRE_STUDY_JIT_COMPILE 0x0001 #define PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE 0x0002 #define PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE 0x0004 +#define PCRE_STUDY_EXTRA_NEEDED 0x0008 -/* Bit flags for the pcre[16]_extra structure. Do not re-arrange or redefine +/* Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine these bits, just add new ones on the end, in order to remain compatible. */ #define PCRE_EXTRA_STUDY_DATA 0x0001 @@ -279,12 +327,18 @@ typedef struct real_pcre pcre; struct real_pcre16; /* declaration; the definition is private */ typedef struct real_pcre16 pcre16; +struct real_pcre32; /* declaration; the definition is private */ +typedef struct real_pcre32 pcre32; + struct real_pcre_jit_stack; /* declaration; the definition is private */ typedef struct real_pcre_jit_stack pcre_jit_stack; struct real_pcre16_jit_stack; /* declaration; the definition is private */ typedef struct real_pcre16_jit_stack pcre16_jit_stack; +struct real_pcre32_jit_stack; /* declaration; the definition is private */ +typedef struct real_pcre32_jit_stack pcre32_jit_stack; + /* If PCRE is compiled with 16 bit character support, PCRE_UCHAR16 must contain a 16 bit wide signed data type. Otherwise it can be a dummy data type since pcre16 functions are not implemented. There is a check for this in pcre_internal.h. */ @@ -296,6 +350,17 @@ pcre16 functions are not implemented. There is a check for this in pcre_internal #define PCRE_SPTR16 const PCRE_UCHAR16 * #endif +/* If PCRE is compiled with 32 bit character support, PCRE_UCHAR32 must contain +a 32 bit wide signed data type. Otherwise it can be a dummy data type since +pcre32 functions are not implemented. There is a check for this in pcre_internal.h. */ +#ifndef PCRE_UCHAR32 +#define PCRE_UCHAR32 unsigned int +#endif + +#ifndef PCRE_SPTR32 +#define PCRE_SPTR32 const PCRE_UCHAR32 * +#endif + /* When PCRE is compiled as a C++ library, the subject pointer type can be replaced with a custom type. For conventional use, the public interface is a const char *. */ @@ -332,6 +397,19 @@ typedef struct pcre16_extra { void *executable_jit; /* Contains a pointer to a compiled jit code */ } pcre16_extra; +/* Same structure as above, but with 32 bit char pointers. */ + +typedef struct pcre32_extra { + unsigned long int flags; /* Bits for which fields are set */ + void *study_data; /* Opaque data from pcre_study() */ + unsigned long int match_limit; /* Maximum number of calls to match() */ + void *callout_data; /* Data passed back in callouts */ + const unsigned char *tables; /* Pointer to character tables */ + unsigned long int match_limit_recursion; /* Max recursive calls to match() */ + PCRE_UCHAR32 **mark; /* For passing back a mark pointer */ + void *executable_jit; /* Contains a pointer to a compiled jit code */ +} pcre32_extra; + /* The structure for passing out data via the pcre_callout_function. We use a structure so that new fields can be added on the end in future versions, without changing the API of the function, thereby allowing old clients to work @@ -379,6 +457,28 @@ typedef struct pcre16_callout_block { /* ------------------------------------------------------------------ */ } pcre16_callout_block; +/* Same structure as above, but with 32 bit char pointers. */ + +typedef struct pcre32_callout_block { + int version; /* Identifies version of block */ + /* ------------------------ Version 0 ------------------------------- */ + int callout_number; /* Number compiled into pattern */ + int *offset_vector; /* The offset vector */ + PCRE_SPTR32 subject; /* The subject being matched */ + int subject_length; /* The length of the subject */ + int start_match; /* Offset to start of this match attempt */ + int current_position; /* Where we currently are in the subject */ + int capture_top; /* Max current capture */ + int capture_last; /* Most recently closed capture */ + void *callout_data; /* Data passed in with the call */ + /* ------------------- Added for Version 1 -------------------------- */ + int pattern_position; /* Offset to next item in the pattern */ + int next_item_length; /* Length of next item in the pattern */ + /* ------------------- Added for Version 2 -------------------------- */ + const PCRE_UCHAR32 *mark; /* Pointer to current mark or NULL */ + /* ------------------------------------------------------------------ */ +} pcre32_callout_block; + /* Indirection for store get and free functions. These can be set to alternative malloc/free functions if required. Special ones are used in the non-recursive case for "frames". There is also an optional callout function @@ -397,6 +497,12 @@ PCRE_EXP_DECL void (*pcre16_free)(void *); PCRE_EXP_DECL void *(*pcre16_stack_malloc)(size_t); PCRE_EXP_DECL void (*pcre16_stack_free)(void *); PCRE_EXP_DECL int (*pcre16_callout)(pcre16_callout_block *); + +PCRE_EXP_DECL void *(*pcre32_malloc)(size_t); +PCRE_EXP_DECL void (*pcre32_free)(void *); +PCRE_EXP_DECL void *(*pcre32_stack_malloc)(size_t); +PCRE_EXP_DECL void (*pcre32_stack_free)(void *); +PCRE_EXP_DECL int (*pcre32_callout)(pcre32_callout_block *); #else /* VPCOMPAT */ PCRE_EXP_DECL void *pcre_malloc(size_t); PCRE_EXP_DECL void pcre_free(void *); @@ -409,12 +515,19 @@ PCRE_EXP_DECL void pcre16_free(void *); PCRE_EXP_DECL void *pcre16_stack_malloc(size_t); PCRE_EXP_DECL void pcre16_stack_free(void *); PCRE_EXP_DECL int pcre16_callout(pcre16_callout_block *); + +PCRE_EXP_DECL void *pcre32_malloc(size_t); +PCRE_EXP_DECL void pcre32_free(void *); +PCRE_EXP_DECL void *pcre32_stack_malloc(size_t); +PCRE_EXP_DECL void pcre32_stack_free(void *); +PCRE_EXP_DECL int pcre32_callout(pcre32_callout_block *); #endif /* VPCOMPAT */ /* User defined callback which provides a stack just before the match starts. */ typedef pcre_jit_stack *(*pcre_jit_callback)(void *); typedef pcre16_jit_stack *(*pcre16_jit_callback)(void *); +typedef pcre32_jit_stack *(*pcre32_jit_callback)(void *); /* Exported PCRE functions */ @@ -422,83 +535,134 @@ PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *, const unsigned char *); PCRE_EXP_DECL pcre16 *pcre16_compile(PCRE_SPTR16, int, const char **, int *, const unsigned char *); +PCRE_EXP_DECL pcre32 *pcre32_compile(PCRE_SPTR32, int, const char **, int *, + const unsigned char *); PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **, int *, const unsigned char *); PCRE_EXP_DECL pcre16 *pcre16_compile2(PCRE_SPTR16, int, int *, const char **, int *, const unsigned char *); +PCRE_EXP_DECL pcre32 *pcre32_compile2(PCRE_SPTR32, int, int *, const char **, + int *, const unsigned char *); PCRE_EXP_DECL int pcre_config(int, void *); PCRE_EXP_DECL int pcre16_config(int, void *); +PCRE_EXP_DECL int pcre32_config(int, void *); PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *, int *, int, const char *, char *, int); PCRE_EXP_DECL int pcre16_copy_named_substring(const pcre16 *, PCRE_SPTR16, int *, int, PCRE_SPTR16, PCRE_UCHAR16 *, int); +PCRE_EXP_DECL int pcre32_copy_named_substring(const pcre32 *, PCRE_SPTR32, + int *, int, PCRE_SPTR32, PCRE_UCHAR32 *, int); PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int, char *, int); PCRE_EXP_DECL int pcre16_copy_substring(PCRE_SPTR16, int *, int, int, PCRE_UCHAR16 *, int); +PCRE_EXP_DECL int pcre32_copy_substring(PCRE_SPTR32, int *, int, int, + PCRE_UCHAR32 *, int); PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *, const char *, int, int, int, int *, int , int *, int); PCRE_EXP_DECL int pcre16_dfa_exec(const pcre16 *, const pcre16_extra *, PCRE_SPTR16, int, int, int, int *, int , int *, int); +PCRE_EXP_DECL int pcre32_dfa_exec(const pcre32 *, const pcre32_extra *, + PCRE_SPTR32, int, int, int, int *, int , int *, int); PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR, int, int, int, int *, int); PCRE_EXP_DECL int pcre16_exec(const pcre16 *, const pcre16_extra *, PCRE_SPTR16, int, int, int, int *, int); +PCRE_EXP_DECL int pcre32_exec(const pcre32 *, const pcre32_extra *, + PCRE_SPTR32, int, int, int, int *, int); +PCRE_EXP_DECL int pcre_jit_exec(const pcre *, const pcre_extra *, + PCRE_SPTR, int, int, int, int *, int, + pcre_jit_stack *); +PCRE_EXP_DECL int pcre16_jit_exec(const pcre16 *, const pcre16_extra *, + PCRE_SPTR16, int, int, int, int *, int, + pcre16_jit_stack *); +PCRE_EXP_DECL int pcre32_jit_exec(const pcre32 *, const pcre32_extra *, + PCRE_SPTR32, int, int, int, int *, int, + pcre32_jit_stack *); PCRE_EXP_DECL void pcre_free_substring(const char *); PCRE_EXP_DECL void pcre16_free_substring(PCRE_SPTR16); +PCRE_EXP_DECL void pcre32_free_substring(PCRE_SPTR32); PCRE_EXP_DECL void pcre_free_substring_list(const char **); PCRE_EXP_DECL void pcre16_free_substring_list(PCRE_SPTR16 *); +PCRE_EXP_DECL void pcre32_free_substring_list(PCRE_SPTR32 *); PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int, void *); PCRE_EXP_DECL int pcre16_fullinfo(const pcre16 *, const pcre16_extra *, int, void *); +PCRE_EXP_DECL int pcre32_fullinfo(const pcre32 *, const pcre32_extra *, int, + void *); PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *, int *, int, const char *, const char **); PCRE_EXP_DECL int pcre16_get_named_substring(const pcre16 *, PCRE_SPTR16, int *, int, PCRE_SPTR16, PCRE_SPTR16 *); +PCRE_EXP_DECL int pcre32_get_named_substring(const pcre32 *, PCRE_SPTR32, + int *, int, PCRE_SPTR32, PCRE_SPTR32 *); PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *); PCRE_EXP_DECL int pcre16_get_stringnumber(const pcre16 *, PCRE_SPTR16); +PCRE_EXP_DECL int pcre32_get_stringnumber(const pcre32 *, PCRE_SPTR32); PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *, char **, char **); PCRE_EXP_DECL int pcre16_get_stringtable_entries(const pcre16 *, PCRE_SPTR16, PCRE_UCHAR16 **, PCRE_UCHAR16 **); +PCRE_EXP_DECL int pcre32_get_stringtable_entries(const pcre32 *, PCRE_SPTR32, + PCRE_UCHAR32 **, PCRE_UCHAR32 **); PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int, const char **); PCRE_EXP_DECL int pcre16_get_substring(PCRE_SPTR16, int *, int, int, PCRE_SPTR16 *); +PCRE_EXP_DECL int pcre32_get_substring(PCRE_SPTR32, int *, int, int, + PCRE_SPTR32 *); PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int, const char ***); PCRE_EXP_DECL int pcre16_get_substring_list(PCRE_SPTR16, int *, int, PCRE_SPTR16 **); +PCRE_EXP_DECL int pcre32_get_substring_list(PCRE_SPTR32, int *, int, + PCRE_SPTR32 **); PCRE_EXP_DECL const unsigned char *pcre_maketables(void); PCRE_EXP_DECL const unsigned char *pcre16_maketables(void); +PCRE_EXP_DECL const unsigned char *pcre32_maketables(void); PCRE_EXP_DECL int pcre_refcount(pcre *, int); PCRE_EXP_DECL int pcre16_refcount(pcre16 *, int); +PCRE_EXP_DECL int pcre32_refcount(pcre32 *, int); PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **); PCRE_EXP_DECL pcre16_extra *pcre16_study(const pcre16 *, int, const char **); +PCRE_EXP_DECL pcre32_extra *pcre32_study(const pcre32 *, int, const char **); PCRE_EXP_DECL void pcre_free_study(pcre_extra *); PCRE_EXP_DECL void pcre16_free_study(pcre16_extra *); +PCRE_EXP_DECL void pcre32_free_study(pcre32_extra *); PCRE_EXP_DECL const char *pcre_version(void); PCRE_EXP_DECL const char *pcre16_version(void); +PCRE_EXP_DECL const char *pcre32_version(void); /* Utility functions for byte order swaps. */ PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *, pcre_extra *, const unsigned char *); PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *, pcre16_extra *, const unsigned char *); +PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *, pcre32_extra *, + const unsigned char *); PCRE_EXP_DECL int pcre16_utf16_to_host_byte_order(PCRE_UCHAR16 *, PCRE_SPTR16, int, int *, int); +PCRE_EXP_DECL int pcre32_utf32_to_host_byte_order(PCRE_UCHAR32 *, + PCRE_SPTR32, int, int *, int); /* JIT compiler related functions. */ PCRE_EXP_DECL pcre_jit_stack *pcre_jit_stack_alloc(int, int); PCRE_EXP_DECL pcre16_jit_stack *pcre16_jit_stack_alloc(int, int); +PCRE_EXP_DECL pcre32_jit_stack *pcre32_jit_stack_alloc(int, int); PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *); PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *); +PCRE_EXP_DECL void pcre32_jit_stack_free(pcre32_jit_stack *); PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *, pcre_jit_callback, void *); PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *, pcre16_jit_callback, void *); +PCRE_EXP_DECL void pcre32_assign_jit_stack(pcre32_extra *, + pcre32_jit_callback, void *); +PCRE_EXP_DECL void pcre_jit_free_unused_memory(void); +PCRE_EXP_DECL void pcre16_jit_free_unused_memory(void); +PCRE_EXP_DECL void pcre32_jit_free_unused_memory(void); #ifdef __cplusplus } /* extern "C" */ diff --git a/src/3rd/pcre/pcrebyte.c b/src/3rd/pcre/pcrebyte.c index 2ada8f79f0..4dfbaae82e 100644 --- a/src/3rd/pcre/pcrebyte.c +++ b/src/3rd/pcre/pcrebyte.c @@ -6,7 +6,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2012 University of Cambridge + Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -95,12 +95,15 @@ Arguments: Returns: 0 if the swap is successful, negative on error */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *argument_re, pcre_extra *extra_data, const unsigned char *tables) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *argument_re, pcre16_extra *extra_data, const unsigned char *tables) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *argument_re, + pcre32_extra *extra_data, const unsigned char *tables) #endif { REAL_PCRE *re = (REAL_PCRE *)argument_re; @@ -108,10 +111,10 @@ pcre_study_data *study; #ifndef COMPILE_PCRE8 pcre_uchar *ptr; int length; -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && defined COMPILE_PCRE16 BOOL utf; BOOL utf16_char; -#endif /* SUPPORT_UTF */ +#endif /* SUPPORT_UTF && COMPILE_PCRE16 */ #endif /* !COMPILE_PCRE8 */ if (re == NULL) return PCRE_ERROR_NULL; @@ -123,16 +126,26 @@ if (re->magic_number == MAGIC_NUMBER) } if (re->magic_number != REVERSED_MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; -if ((swap_uint16(re->flags) & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE; +if ((swap_uint32(re->flags) & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE; re->magic_number = MAGIC_NUMBER; re->size = swap_uint32(re->size); re->options = swap_uint32(re->options); -re->flags = swap_uint16(re->flags); -re->top_bracket = swap_uint16(re->top_bracket); -re->top_backref = swap_uint16(re->top_backref); +re->flags = swap_uint32(re->flags); +re->limit_match = swap_uint32(re->limit_match); +re->limit_recursion = swap_uint32(re->limit_recursion); + +#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 re->first_char = swap_uint16(re->first_char); re->req_char = swap_uint16(re->req_char); +#elif defined COMPILE_PCRE32 +re->first_char = swap_uint32(re->first_char); +re->req_char = swap_uint32(re->req_char); +#endif + +re->max_lookbehind = swap_uint16(re->max_lookbehind); +re->top_bracket = swap_uint16(re->top_bracket); +re->top_backref = swap_uint16(re->top_backref); re->name_table_offset = swap_uint16(re->name_table_offset); re->name_entry_size = swap_uint16(re->name_entry_size); re->name_count = swap_uint16(re->name_count); @@ -150,20 +163,24 @@ if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0) #ifndef COMPILE_PCRE8 ptr = (pcre_uchar *)re + re->name_table_offset; length = re->name_count * re->name_entry_size; -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && defined COMPILE_PCRE16 utf = (re->options & PCRE_UTF16) != 0; utf16_char = FALSE; -#endif +#endif /* SUPPORT_UTF && COMPILE_PCRE16 */ while(TRUE) { /* Swap previous characters. */ while (length-- > 0) { +#if defined COMPILE_PCRE16 *ptr = swap_uint16(*ptr); +#elif defined COMPILE_PCRE32 + *ptr = swap_uint32(*ptr); +#endif ptr++; } -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && defined COMPILE_PCRE16 if (utf16_char) { if (HAS_EXTRALEN(ptr[-1])) @@ -178,13 +195,17 @@ while(TRUE) /* Get next opcode. */ length = 0; +#if defined COMPILE_PCRE16 *ptr = swap_uint16(*ptr); +#elif defined COMPILE_PCRE32 + *ptr = swap_uint32(*ptr); +#endif switch (*ptr) { case OP_END: return 0; -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && defined COMPILE_PCRE16 case OP_CHAR: case OP_CHARI: case OP_NOT: @@ -259,16 +280,26 @@ while(TRUE) case OP_XCLASS: /* Reverse the size of the XCLASS instance. */ ptr++; +#if defined COMPILE_PCRE16 *ptr = swap_uint16(*ptr); +#elif defined COMPILE_PCRE32 + *ptr = swap_uint32(*ptr); +#endif +#ifndef COMPILE_PCRE32 if (LINK_SIZE > 1) { /* LINK_SIZE can be 1 or 2 in 16 bit mode. */ ptr++; *ptr = swap_uint16(*ptr); } +#endif ptr++; length = (GET(ptr, -LINK_SIZE)) - (1 + LINK_SIZE + 1); +#if defined COMPILE_PCRE16 *ptr = swap_uint16(*ptr); +#elif defined COMPILE_PCRE32 + *ptr = swap_uint32(*ptr); +#endif if ((*ptr & XCL_MAP) != 0) { /* Skip the character bit map. */ @@ -279,7 +310,7 @@ while(TRUE) } ptr++; } -/* Control should never reach here in 16 bit mode. */ +/* Control should never reach here in 16/32 bit mode. */ #endif /* !COMPILE_PCRE8 */ return 0; diff --git a/src/3rd/pcre/pcrecomp.c b/src/3rd/pcre/pcrecomp.c index 9896d37e27..6a75a6cf03 100644 --- a/src/3rd/pcre/pcrecomp.c +++ b/src/3rd/pcre/pcrecomp.c @@ -6,7 +6,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2012 University of Cambridge + Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -53,7 +53,7 @@ supporting internal functions that are not used by other modules. */ #include "pcreinal.h" -/* When PCRE_DEBUG is defined, we need the pcre(16)_printint() function, which +/* When PCRE_DEBUG is defined, we need the pcre(16|32)_printint() function, which is also used by pcretest. PCRE_DEBUG is not defined when building a production library. We do not need to select pcre16_printint.c specially, because the COMPILE_PCREx macro will already be appropriately set. */ @@ -68,7 +68,7 @@ COMPILE_PCREx macro will already be appropriately set. */ /* Macro for setting individual bits in class bitmaps. */ -#define SETBIT(a,b) a[b/8] |= (1 << (b%8)) +#define SETBIT(a,b) a[(b)/8] |= (1 << ((b)&7)) /* Maximum length value to check against when making sure that the integer that holds the compiled pattern length does not overflow. We make it a bit less than @@ -77,6 +77,18 @@ to check them every time. */ #define OFLOW_MAX (INT_MAX - 20) +/* Definitions to allow mutual recursion */ + +static int + add_list_to_class(pcre_uint8 *, pcre_uchar **, int, compile_data *, + const pcre_uint32 *, unsigned int); + +static BOOL + compile_regex(int, pcre_uchar **, const pcre_uchar **, int *, BOOL, BOOL, int, int, + pcre_uint32 *, pcre_int32 *, pcre_uint32 *, pcre_int32 *, branch_chain *, + compile_data *, int *); + + /************************************************* * Code parameters and static tables * @@ -103,6 +115,13 @@ kicks in at the same number of forward references in all cases. */ #define COMPILE_WORK_SIZE (2048*LINK_SIZE) #define COMPILE_WORK_SIZE_MAX (100*COMPILE_WORK_SIZE) +/* This value determines the size of the initial vector that is used for +remembering named groups during the pre-compile. It is allocated on the stack, +but if it is too small, it is expanded using malloc(), in a similar way to the +workspace. The value is the number of slots in the list. */ + +#define NAMED_GROUP_LIST_SIZE 20 + /* The overrun tests check for a slightly smaller size so that they detect the overrun before it actually does run off the end of the data block. */ @@ -110,8 +129,11 @@ overrun before it actually does run off the end of the data block. */ /* Private flags added to firstchar and reqchar. */ -#define REQ_CASELESS 0x10000000l /* Indicates caselessness */ -#define REQ_VARY 0x20000000l /* Reqchar followed non-literal item */ +#define REQ_CASELESS (1 << 0) /* Indicates caselessness */ +#define REQ_VARY (1 << 1) /* Reqchar followed non-literal item */ +/* Negative values for the firstchar and reqchar flags */ +#define REQ_UNSET (-2) +#define REQ_NONE (-1) /* Repeated character flags. */ @@ -238,11 +260,25 @@ static const verbitem verbs[] = { static const int verbcount = sizeof(verbs)/sizeof(verbitem); +/* Substitutes for [[:<:]] and [[:>:]], which mean start and end of word in +another regex library. */ + +static const pcre_uchar sub_start_of_word[] = { + CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, + CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, CHAR_RIGHT_PARENTHESIS, '\0' }; + +static const pcre_uchar sub_end_of_word[] = { + CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, + CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, + CHAR_RIGHT_PARENTHESIS, '\0' }; + + /* Tables of names of POSIX character classes and their lengths. The names are now all in a single string, to reduce the number of relocations when a shared library is dynamically loaded. The list of lengths is terminated by a zero length entry. The first three must be alpha, lower, upper, as this is assumed -for handling case independence. */ +for handling case independence. The indices for graph, print, and punct are +needed, so identify them. */ static const char posix_names[] = STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0 @@ -253,6 +289,11 @@ static const char posix_names[] = static const pcre_uint8 posix_name_lengths[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; +#define PC_GRAPH 8 +#define PC_PRINT 9 +#define PC_PUNCT 10 + + /* Table of class bit maps for each POSIX class. Each class is formed from a base map, with an optional addition or removal of another map. Then, for some classes, there is some additional tweaking: for [:blank:] the vertical space @@ -280,9 +321,8 @@ static const int posix_class_maps[] = { cbit_xdigit,-1, 0 /* xdigit */ }; -/* Table of substitutes for \d etc when PCRE_UCP is set. The POSIX class -substitutes must be in the order of the names, defined above, and there are -both positive and negative cases. NULL means no substitute. */ +/* Table of substitutes for \d etc when PCRE_UCP is set. They are replaced by +Unicode property escapes. */ #ifdef SUPPORT_UCP static const pcre_uchar string_PNd[] = { @@ -307,12 +347,18 @@ static const pcre_uchar string_pXwd[] = { static const pcre_uchar *substitutes[] = { string_PNd, /* \D */ string_pNd, /* \d */ - string_PXsp, /* \S */ /* NOTE: Xsp is Perl space */ - string_pXsp, /* \s */ + string_PXsp, /* \S */ /* Xsp is Perl space, but from 8.34, Perl */ + string_pXsp, /* \s */ /* space and POSIX space are the same. */ string_PXwd, /* \W */ string_pXwd /* \w */ }; +/* The POSIX class substitutes must be in the order of the POSIX class names, +defined above, and there are both positive and negative cases. NULL means no +general substitute of a Unicode property escape (\p or \P). However, for some +POSIX classes (e.g. graph, print, punct) a special property code is compiled +directly. */ + static const pcre_uchar string_pL[] = { CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' }; @@ -360,8 +406,8 @@ static const pcre_uchar *posix_substitutes[] = { NULL, /* graph */ NULL, /* print */ NULL, /* punct */ - string_pXps, /* space */ /* NOTE: Xps is POSIX space */ - string_pXwd, /* word */ + string_pXps, /* space */ /* Xps is POSIX space, but from 8.34 */ + string_pXwd, /* word */ /* Perl and POSIX space are the same */ NULL, /* xdigit */ /* Negated cases */ string_PL, /* ^alpha */ @@ -375,8 +421,8 @@ static const pcre_uchar *posix_substitutes[] = { NULL, /* ^graph */ NULL, /* ^print */ NULL, /* ^punct */ - string_PXps, /* ^space */ /* NOTE: Xps is POSIX space */ - string_PXwd, /* ^word */ + string_PXps, /* ^space */ /* Xps is POSIX space, but from 8.34 */ + string_PXwd, /* ^word */ /* Perl and POSIX space are the same */ NULL /* ^xdigit */ }; #define POSIX_SUBSIZE (sizeof(posix_substitutes) / sizeof(pcre_uchar *)) @@ -440,7 +486,7 @@ static const char error_texts[] = "POSIX collating elements are not supported\0" "this version of PCRE is compiled without UTF support\0" "spare error\0" /** DEAD **/ - "character value in \\x{...} sequence is too large\0" + "character value in \\x{} or \\o{} is too large\0" /* 35 */ "invalid condition (?(0)\0" "\\C not allowed in lookbehind assertion\0" @@ -472,7 +518,7 @@ static const char error_texts[] = "a numbered reference must not be zero\0" "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0" /* 60 */ - "(*VERB) not recognized\0" + "(*VERB) not recognized or malformed\0" "number is too big\0" "subpattern name expected\0" "digit expected after (?+\0" @@ -492,6 +538,15 @@ static const char error_texts[] = /* 75 */ "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0" "character value in \\u.... sequence is too large\0" + "invalid UTF-32 string\0" + "setting UTF is disabled by the application\0" + "non-hex character in \\x{} (closing brace missing?)\0" + /* 80 */ + "non-octal character in \\o{} (closing brace missing?)\0" + "missing opening brace after \\o\0" + "parentheses are too deeply nested\0" + "invalid range in character class\0" + "group name must start with a non-digit\0" ; /* Table to identify digits and hex digits. This is used when compiling @@ -631,11 +686,181 @@ static const pcre_uint8 ebcdic_chartab[] = { /* chartable partial dup */ #endif -/* Definition to allow mutual recursion */ +/* This table is used to check whether auto-possessification is possible +between adjacent character-type opcodes. The left-hand (repeated) opcode is +used to select the row, and the right-hand opcode is use to select the column. +A value of 1 means that auto-possessification is OK. For example, the second +value in the first row means that \D+\d can be turned into \D++\d. -static BOOL - compile_regex(int, pcre_uchar **, const pcre_uchar **, int *, BOOL, BOOL, int, int, - int *, int *, branch_chain *, compile_data *, int *); +The Unicode property types (\P and \p) have to be present to fill out the table +because of what their opcode values are, but the table values should always be +zero because property types are handled separately in the code. The last four +columns apply to items that cannot be repeated, so there is no need to have +rows for them. Note that OP_DIGIT etc. are generated only when PCRE_UCP is +*not* set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */ + +#define APTROWS (LAST_AUTOTAB_LEFT_OP - FIRST_AUTOTAB_OP + 1) +#define APTCOLS (LAST_AUTOTAB_RIGHT_OP - FIRST_AUTOTAB_OP + 1) + +static const pcre_uint8 autoposstab[APTROWS][APTCOLS] = { +/* \D \d \S \s \W \w . .+ \C \P \p \R \H \h \V \v \X \Z \z $ $M */ + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \D */ + { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \d */ + { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \S */ + { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \s */ + { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \W */ + { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \w */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* . */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* .+ */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \C */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \P */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \p */ + { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \R */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \H */ + { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \h */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \V */ + { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, /* \v */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 } /* \X */ +}; + + +/* This table is used to check whether auto-possessification is possible +between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP). The +left-hand (repeated) opcode is used to select the row, and the right-hand +opcode is used to select the column. The values are as follows: + + 0 Always return FALSE (never auto-possessify) + 1 Character groups are distinct (possessify if both are OP_PROP) + 2 Check character categories in the same group (general or particular) + 3 TRUE if the two opcodes are not the same (PROP vs NOTPROP) + + 4 Check left general category vs right particular category + 5 Check right general category vs left particular category + + 6 Left alphanum vs right general category + 7 Left space vs right general category + 8 Left word vs right general category + + 9 Right alphanum vs left general category + 10 Right space vs left general category + 11 Right word vs left general category + + 12 Left alphanum vs right particular category + 13 Left space vs right particular category + 14 Left word vs right particular category + + 15 Right alphanum vs left particular category + 16 Right space vs left particular category + 17 Right word vs left particular category +*/ + +static const pcre_uint8 propposstab[PT_TABSIZE][PT_TABSIZE] = { +/* ANY LAMP GC PC SC ALNUM SPACE PXSPACE WORD CLIST UCNC */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_ANY */ + { 0, 3, 0, 0, 0, 3, 1, 1, 0, 0, 0 }, /* PT_LAMP */ + { 0, 0, 2, 4, 0, 9, 10, 10, 11, 0, 0 }, /* PT_GC */ + { 0, 0, 5, 2, 0, 15, 16, 16, 17, 0, 0 }, /* PT_PC */ + { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, /* PT_SC */ + { 0, 3, 6, 12, 0, 3, 1, 1, 0, 0, 0 }, /* PT_ALNUM */ + { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_SPACE */ + { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_PXSPACE */ + { 0, 0, 8, 14, 0, 0, 1, 1, 3, 0, 0 }, /* PT_WORD */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_CLIST */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 } /* PT_UCNC */ +}; + +/* This table is used to check whether auto-possessification is possible +between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP) when one +specifies a general category and the other specifies a particular category. The +row is selected by the general category and the column by the particular +category. The value is 1 if the particular category is not part of the general +category. */ + +static const pcre_uint8 catposstab[7][30] = { +/* Cc Cf Cn Co Cs Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc Pd Pe Pf Pi Po Ps Sc Sk Sm So Zl Zp Zs */ + { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* C */ + { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* L */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* M */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* N */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }, /* P */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1 }, /* S */ + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 } /* Z */ +}; + +/* This table is used when checking ALNUM, (PX)SPACE, SPACE, and WORD against +a general or particular category. The properties in each row are those +that apply to the character set in question. Duplication means that a little +unnecessary work is done when checking, but this keeps things much simpler +because they can all use the same code. For more details see the comment where +this table is used. + +Note: SPACE and PXSPACE used to be different because Perl excluded VT from +"space", but from Perl 5.18 it's included, so both categories are treated the +same here. */ + +static const pcre_uint8 posspropstab[3][4] = { + { ucp_L, ucp_N, ucp_N, ucp_Nl }, /* ALNUM, 3rd and 4th values redundant */ + { ucp_Z, ucp_Z, ucp_C, ucp_Cc }, /* SPACE and PXSPACE, 2nd value redundant */ + { ucp_L, ucp_N, ucp_P, ucp_Po } /* WORD */ +}; + +/* This table is used when converting repeating opcodes into possessified +versions as a result of an explicit possessive quantifier such as ++. A zero +value means there is no possessified version - in those cases the item in +question must be wrapped in ONCE brackets. The table is truncated at OP_CALLOUT +because all relevant opcodes are less than that. */ + +static const pcre_uint8 opcode_possessify[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */ + + 0, /* NOTI */ + OP_POSSTAR, 0, /* STAR, MINSTAR */ + OP_POSPLUS, 0, /* PLUS, MINPLUS */ + OP_POSQUERY, 0, /* QUERY, MINQUERY */ + OP_POSUPTO, 0, /* UPTO, MINUPTO */ + 0, /* EXACT */ + 0, 0, 0, 0, /* POS{STAR,PLUS,QUERY,UPTO} */ + + OP_POSSTARI, 0, /* STARI, MINSTARI */ + OP_POSPLUSI, 0, /* PLUSI, MINPLUSI */ + OP_POSQUERYI, 0, /* QUERYI, MINQUERYI */ + OP_POSUPTOI, 0, /* UPTOI, MINUPTOI */ + 0, /* EXACTI */ + 0, 0, 0, 0, /* POS{STARI,PLUSI,QUERYI,UPTOI} */ + + OP_NOTPOSSTAR, 0, /* NOTSTAR, NOTMINSTAR */ + OP_NOTPOSPLUS, 0, /* NOTPLUS, NOTMINPLUS */ + OP_NOTPOSQUERY, 0, /* NOTQUERY, NOTMINQUERY */ + OP_NOTPOSUPTO, 0, /* NOTUPTO, NOTMINUPTO */ + 0, /* NOTEXACT */ + 0, 0, 0, 0, /* NOTPOS{STAR,PLUS,QUERY,UPTO} */ + + OP_NOTPOSSTARI, 0, /* NOTSTARI, NOTMINSTARI */ + OP_NOTPOSPLUSI, 0, /* NOTPLUSI, NOTMINPLUSI */ + OP_NOTPOSQUERYI, 0, /* NOTQUERYI, NOTMINQUERYI */ + OP_NOTPOSUPTOI, 0, /* NOTUPTOI, NOTMINUPTOI */ + 0, /* NOTEXACTI */ + 0, 0, 0, 0, /* NOTPOS{STARI,PLUSI,QUERYI,UPTOI} */ + + OP_TYPEPOSSTAR, 0, /* TYPESTAR, TYPEMINSTAR */ + OP_TYPEPOSPLUS, 0, /* TYPEPLUS, TYPEMINPLUS */ + OP_TYPEPOSQUERY, 0, /* TYPEQUERY, TYPEMINQUERY */ + OP_TYPEPOSUPTO, 0, /* TYPEUPTO, TYPEMINUPTO */ + 0, /* TYPEEXACT */ + 0, 0, 0, 0, /* TYPEPOS{STAR,PLUS,QUERY,UPTO} */ + + OP_CRPOSSTAR, 0, /* CRSTAR, CRMINSTAR */ + OP_CRPOSPLUS, 0, /* CRPLUS, CRMINPLUS */ + OP_CRPOSQUERY, 0, /* CRQUERY, CRMINQUERY */ + OP_CRPOSRANGE, 0, /* CRRANGE, CRMINRANGE */ + 0, 0, 0, 0, /* CRPOS{STAR,PLUS,QUERY,RANGE} */ + + 0, 0, 0, /* CLASS, NCLASS, XCLASS */ + 0, 0, /* REF, REFI */ + 0, 0, /* DNREF, DNREFI */ + 0, 0 /* RECURSE, CALLOUT */ +}; @@ -658,13 +883,14 @@ find_error_text(int n) const char *s = error_texts; for (; n > 0; n--) { - while (*s++ != 0) {}; - if (*s == 0) return "Error text not found (please report)"; + while (*s++ != CHAR_NULL) {}; + if (*s == CHAR_NULL) return "Error text not found (please report)"; } return s; } + /************************************************* * Expand the workspace * *************************************************/ @@ -742,33 +968,35 @@ return (*p == CHAR_RIGHT_CURLY_BRACKET); *************************************************/ /* This function is called when a \ has been encountered. It either returns a -positive value for a simple escape such as \n, or a negative value which -encodes one of the more complicated things such as \d. A backreference to group -n is returned as -(ESC_REF + n); ESC_REF is the highest ESC_xxx macro. When -UTF-8 is enabled, a positive value greater than 255 may be returned. On entry, -ptr is pointing at the \. On exit, it is on the final character of the escape -sequence. +positive value for a simple escape such as \n, or 0 for a data character which +will be placed in chptr. A backreference to group n is returned as negative n. +When UTF-8 is enabled, a positive value greater than 255 may be returned in +chptr. On entry, ptr is pointing at the \. On exit, it is on the final +character of the escape sequence. Arguments: ptrptr points to the pattern position pointer + chptr points to a returned data character errorcodeptr points to the errorcode variable bracount number of previous extracting brackets options the options bits isclass TRUE if inside a character class -Returns: zero or positive => a data character - negative => a special escape sequence +Returns: zero => a data character + positive => a special escape sequence + negative => a back reference on error, errorcodeptr is set */ static int -check_escape(const pcre_uchar **ptrptr, int *errorcodeptr, int bracount, - int options, BOOL isclass) +check_escape(const pcre_uchar **ptrptr, pcre_uint32 *chptr, int *errorcodeptr, + int bracount, int options, BOOL isclass) { /* PCRE_UTF16 has the same value as PCRE_UTF8. */ BOOL utf = (options & PCRE_UTF8) != 0; const pcre_uchar *ptr = *ptrptr + 1; -pcre_int32 c; +pcre_uint32 c; +int escape = 0; int i; GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ @@ -776,7 +1004,7 @@ ptr--; /* Set pointer back to the last byte */ /* If backslash is at the end of the pattern, it's an error. */ -if (c == 0) *errorcodeptr = ERR1; +if (c == CHAR_NULL) *errorcodeptr = ERR1; /* Non-alphanumerics are literals. For digits or letters, do an initial lookup in a table. A non-zero result is something that can be returned immediately. @@ -785,12 +1013,13 @@ Otherwise further processing may be required. */ #ifndef EBCDIC /* ASCII/UTF-8 coding */ /* Not alphanumeric */ else if (c < CHAR_0 || c > CHAR_z) {} -else if ((i = escapes[c - CHAR_0]) != 0) c = i; +else if ((i = escapes[c - CHAR_0]) != 0) + { if (i > 0) c = (pcre_uint32)i; else escape = -i; } #else /* EBCDIC coding */ /* Not alphanumeric */ -else if (c < 'a' || (!MAX_255(c) || (ebcdic_chartab[c] & 0x0E) == 0)) {} -else if ((i = escapes[c - 0x48]) != 0) c = i; +else if (c < CHAR_a || (!MAX_255(c) || (ebcdic_chartab[c] & 0x0E) == 0)) {} +else if ((i = escapes[c - 0x48]) != 0) { if (i > 0) c = (pcre_uint32)i; else escape = -i; } #endif /* Escapes that need further processing, or are illegal. */ @@ -798,7 +1027,8 @@ else if ((i = escapes[c - 0x48]) != 0) c = i; else { const pcre_uchar *oldptr; - BOOL braced, negated; + BOOL braced, negated, overflow; + int s; switch (c) { @@ -823,7 +1053,7 @@ else c = 0; for (i = 0; i < 4; ++i) { - register int cc = *(++ptr); + register pcre_uint32 cc = *(++ptr); #ifndef EBCDIC /* ASCII/UTF-8 coding */ if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); @@ -833,12 +1063,12 @@ else #endif } -#ifdef COMPILE_PCRE8 - if (c > (utf ? 0x10ffff : 0xff)) -#else -#ifdef COMPILE_PCRE16 - if (c > (utf ? 0x10ffff : 0xffff)) -#endif +#if defined COMPILE_PCRE8 + if (c > (utf ? 0x10ffffU : 0xffU)) +#elif defined COMPILE_PCRE16 + if (c > (utf ? 0x10ffffU : 0xffffU)) +#elif defined COMPILE_PCRE32 + if (utf && c > 0x10ffffU) #endif { *errorcodeptr = ERR76; @@ -870,13 +1100,13 @@ else (3) For Oniguruma compatibility we also support \g followed by a name or a number either in angle brackets or in single quotes. However, these are (possibly recursive) subroutine calls, _not_ backreferences. Just return - the -ESC_g code (cf \k). */ + the ESC_g code (cf \k). */ case CHAR_g: if (isclass) break; if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE) { - c = -ESC_g; + escape = ESC_g; break; } @@ -885,11 +1115,11 @@ else if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) { const pcre_uchar *p; - for (p = ptr+2; *p != 0 && *p != CHAR_RIGHT_CURLY_BRACKET; p++) + for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++) if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break; - if (*p != 0 && *p != CHAR_RIGHT_CURLY_BRACKET) + if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET) { - c = -ESC_k; + escape = ESC_k; break; } braced = TRUE; @@ -905,17 +1135,18 @@ else else negated = FALSE; /* The integer range is limited by the machine's int representation. */ - c = 0; + s = 0; + overflow = FALSE; while (IS_DIGIT(ptr[1])) { - if (((unsigned int)c) > INT_MAX / 10) /* Integer overflow */ + if (s > INT_MAX / 10 - 1) /* Integer overflow */ { - c = -1; + overflow = TRUE; break; } - c = c * 10 + *(++ptr) - CHAR_0; + s = s * 10 + (int)(*(++ptr) - CHAR_0); } - if (((unsigned int)c) > INT_MAX) /* Integer overflow */ + if (overflow) /* Integer overflow */ { while (IS_DIGIT(ptr[1])) ptr++; @@ -929,7 +1160,7 @@ else break; } - if (c == 0) + if (s == 0) { *errorcodeptr = ERR58; break; @@ -937,28 +1168,32 @@ else if (negated) { - if (c > bracount) + if (s > bracount) { *errorcodeptr = ERR15; break; } - c = bracount - (c - 1); + s = bracount - (s - 1); } - c = -(ESC_REF + c); + escape = -s; break; /* The handling of escape sequences consisting of a string of digits - starting with one that is not zero is not straightforward. By experiment, - the way Perl works seems to be as follows: + starting with one that is not zero is not straightforward. Perl has changed + over the years. Nowadays \g{} for backreferences and \o{} for octal are + recommended to avoid the ambiguities in the old syntax. Outside a character class, the digits are read as a decimal number. If the - number is less than 10, or if there are that many previous extracting - left brackets, then it is a back reference. Otherwise, up to three octal - digits are read to form an escaped byte. Thus \123 is likely to be octal - 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal - value is greater than 377, the least significant 8 bits are taken. Inside a - character class, \ followed by a digit is always an octal number. */ + number is less than 8 (used to be 10), or if there are that many previous + extracting left brackets, then it is a back reference. Otherwise, up to + three octal digits are read to form an escaped byte. Thus \123 is likely to + be octal 123 (cf \0123, which is octal 012 followed by the literal 3). If + the octal value is greater than 377, the least significant 8 bits are + taken. \8 and \9 are treated as the literal characters 8 and 9. + + Inside a character class, \ followed by a digit is always either a literal + 8 or 9 or an octal number. */ case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: @@ -967,41 +1202,40 @@ else { oldptr = ptr; /* The integer range is limited by the machine's int representation. */ - c -= CHAR_0; + s = (int)(c -CHAR_0); + overflow = FALSE; while (IS_DIGIT(ptr[1])) { - if (((unsigned int)c) > INT_MAX / 10) /* Integer overflow */ + if (s > INT_MAX / 10 - 1) /* Integer overflow */ { - c = -1; + overflow = TRUE; break; } - c = c * 10 + *(++ptr) - CHAR_0; + s = s * 10 + (int)(*(++ptr) - CHAR_0); } - if (((unsigned int)c) > INT_MAX) /* Integer overflow */ + if (overflow) /* Integer overflow */ { while (IS_DIGIT(ptr[1])) ptr++; *errorcodeptr = ERR61; break; } - if (c < 10 || c <= bracount) + if (s < 8 || s <= bracount) /* Check for back reference */ { - c = -(ESC_REF + c); + escape = -s; break; } ptr = oldptr; /* Put the pointer back and fall through */ } - /* Handle an octal number following \. If the first digit is 8 or 9, Perl - generates a binary zero byte and treats the digit as a following literal. - Thus we have to pull back the pointer by one. */ + /* Handle a digit following \ when the number is not a back reference. If + the first digit is 8 or 9, Perl used to generate a binary zero byte and + then treat the digit as a following literal. At least by Perl 5.18 this + changed so as not to insert the binary zero. */ - if ((c = *ptr) >= CHAR_8) - { - ptr--; - c = 0; - break; - } + if ((c = *ptr) >= CHAR_8) break; + + /* Fall through with a digit less than 8 */ /* \0 always starts an octal number, but we may drop through to here with a larger first octal digit. The original code used just to take the least @@ -1018,22 +1252,57 @@ else #endif break; - /* \x is complicated. \x{ddd} is a character number which can be greater - than 0xff in utf or non-8bit mode, but only if the ddd are hex digits. - If not, { is treated as a data character. */ + /* \o is a relatively new Perl feature, supporting a more general way of + specifying character codes in octal. The only supported form is \o{ddd}. */ + + case CHAR_o: + if (ptr[1] != CHAR_LEFT_CURLY_BRACKET) *errorcodeptr = ERR81; else + { + ptr += 2; + c = 0; + overflow = FALSE; + while (*ptr >= CHAR_0 && *ptr <= CHAR_7) + { + register pcre_uint32 cc = *ptr++; + if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */ +#ifdef COMPILE_PCRE32 + if (c >= 0x20000000l) { overflow = TRUE; break; } +#endif + c = (c << 3) + cc - CHAR_0 ; +#if defined COMPILE_PCRE8 + if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; } +#elif defined COMPILE_PCRE16 + if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; } +#elif defined COMPILE_PCRE32 + if (utf && c > 0x10ffffU) { overflow = TRUE; break; } +#endif + } + if (overflow) + { + while (*ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++; + *errorcodeptr = ERR34; + } + else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) + { + if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; + } + else *errorcodeptr = ERR80; + } + break; + + /* \x is complicated. In JavaScript, \x must be followed by two hexadecimal + numbers. Otherwise it is a lowercase x letter. */ case CHAR_x: if ((options & PCRE_JAVASCRIPT_COMPAT) != 0) { - /* In JavaScript, \x must be followed by two hexadecimal numbers. - Otherwise it is a lowercase x letter. */ if (MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0 && MAX_255(ptr[2]) && (digitab[ptr[2]] & ctype_xdigit) != 0) { c = 0; for (i = 0; i < 2; ++i) { - register int cc = *(++ptr); + register pcre_uint32 cc = *(++ptr); #ifndef EBCDIC /* ASCII/UTF-8 coding */ if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); @@ -1043,68 +1312,86 @@ else #endif } } - break; - } + } /* End JavaScript handling */ - if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) + /* Handle \x in Perl's style. \x{ddd} is a character number which can be + greater than 0xff in utf or non-8bit mode, but only if the ddd are hex + digits. If not, { used to be treated as a data character. However, Perl + seems to read hex digits up to the first non-such, and ignore the rest, so + that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE + now gives an error. */ + + else { - const pcre_uchar *pt = ptr + 2; - - c = 0; - while (MAX_255(*pt) && (digitab[*pt] & ctype_xdigit) != 0) + if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) { - register int cc = *pt++; - if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */ + ptr += 2; + c = 0; + overflow = FALSE; + while (MAX_255(*ptr) && (digitab[*ptr] & ctype_xdigit) != 0) + { + register pcre_uint32 cc = *ptr++; + if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */ + +#ifdef COMPILE_PCRE32 + if (c >= 0x10000000l) { overflow = TRUE; break; } +#endif #ifndef EBCDIC /* ASCII/UTF-8 coding */ - if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ - c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); + if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ + c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); #else /* EBCDIC coding */ - if (cc >= CHAR_a && cc <= CHAR_z) cc += 64; /* Convert to upper case */ - c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10)); + if (cc >= CHAR_a && cc <= CHAR_z) cc += 64; /* Convert to upper case */ + c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10)); #endif -#ifdef COMPILE_PCRE8 - if (c > (utf ? 0x10ffff : 0xff)) { c = -1; break; } -#else -#ifdef COMPILE_PCRE16 - if (c > (utf ? 0x10ffff : 0xffff)) { c = -1; break; } +#if defined COMPILE_PCRE8 + if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; } +#elif defined COMPILE_PCRE16 + if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; } +#elif defined COMPILE_PCRE32 + if (utf && c > 0x10ffffU) { overflow = TRUE; break; } #endif -#endif - } + } - if (c < 0) + if (overflow) + { + while (MAX_255(*ptr) && (digitab[*ptr] & ctype_xdigit) != 0) ptr++; + *errorcodeptr = ERR34; + } + + else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) + { + if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; + } + + /* If the sequence of hex digits does not end with '}', give an error. + We used just to recognize this construct and fall through to the normal + \x handling, but nowadays Perl gives an error, which seems much more + sensible, so we do too. */ + + else *errorcodeptr = ERR79; + } /* End of \x{} processing */ + + /* Read a single-byte hex-defined char (up to two hex digits after \x) */ + + else { - while (MAX_255(*pt) && (digitab[*pt] & ctype_xdigit) != 0) pt++; - *errorcodeptr = ERR34; - } - - if (*pt == CHAR_RIGHT_CURLY_BRACKET) - { - if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; - ptr = pt; - break; - } - - /* If the sequence of hex digits does not end with '}', then we don't - recognize this construct; fall through to the normal \x handling. */ - } - - /* Read just a single-byte hex-defined char */ - - c = 0; - while (i++ < 2 && MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0) - { - int cc; /* Some compilers don't like */ - cc = *(++ptr); /* ++ in initializers */ + c = 0; + while (i++ < 2 && MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0) + { + pcre_uint32 cc; /* Some compilers don't like */ + cc = *(++ptr); /* ++ in initializers */ #ifndef EBCDIC /* ASCII/UTF-8 coding */ - if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ - c = c * 16 + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); + if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ + c = c * 16 + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); #else /* EBCDIC coding */ - if (cc <= CHAR_z) cc += 64; /* Convert to upper case */ - c = c * 16 + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10)); + if (cc <= CHAR_z) cc += 64; /* Convert to upper case */ + c = c * 16 + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10)); #endif - } + } + } /* End of \xdd handling */ + } /* End of Perl-style \x handling */ break; /* For \c, a following letter is upper-cased; then the 0x40 bit is flipped. @@ -1114,7 +1401,7 @@ else case CHAR_c: c = *(++ptr); - if (c == 0) + if (c == CHAR_NULL) { *errorcodeptr = ERR2; break; @@ -1154,19 +1441,20 @@ else newline". PCRE does not support \N{name}. However, it does support quantification such as \N{2,3}. */ -if (c == -ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET && +if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET && !is_counted_repeat(ptr+2)) *errorcodeptr = ERR37; /* If PCRE_UCP is set, we change the values for \d etc. */ -if ((options & PCRE_UCP) != 0 && c <= -ESC_D && c >= -ESC_w) - c -= (ESC_DU - ESC_D); +if ((options & PCRE_UCP) != 0 && escape >= ESC_D && escape <= ESC_w) + escape += (ESC_DU - ESC_D); /* Set the pointer to the final character before returning. */ *ptrptr = ptr; -return c; +*chptr = c; +return escape; } @@ -1184,21 +1472,24 @@ escape sequence. Argument: ptrptr points to the pattern position pointer negptr points to a boolean that is set TRUE for negation else FALSE - dptr points to an int that is set to the detailed property value + ptypeptr points to an unsigned int that is set to the type value + pdataptr points to an unsigned int that is set to the detailed property value errorcodeptr points to the error code variable -Returns: type value from ucp_type_table, or -1 for an invalid type +Returns: TRUE if the type value was found, or FALSE for an invalid type */ -static int -get_ucp(const pcre_uchar **ptrptr, BOOL *negptr, int *dptr, int *errorcodeptr) +static BOOL +get_ucp(const pcre_uchar **ptrptr, BOOL *negptr, unsigned int *ptypeptr, + unsigned int *pdataptr, int *errorcodeptr) { -int c, i, bot, top; +pcre_uchar c; +int i, bot, top; const pcre_uchar *ptr = *ptrptr; pcre_uchar name[32]; c = *(++ptr); -if (c == 0) goto ERROR_RETURN; +if (c == CHAR_NULL) goto ERROR_RETURN; *negptr = FALSE; @@ -1215,7 +1506,7 @@ if (c == CHAR_LEFT_CURLY_BRACKET) for (i = 0; i < (int)(sizeof(name) / sizeof(pcre_uchar)) - 1; i++) { c = *(++ptr); - if (c == 0) goto ERROR_RETURN; + if (c == CHAR_NULL) goto ERROR_RETURN; if (c == CHAR_RIGHT_CURLY_BRACKET) break; name[i] = c; } @@ -1240,30 +1531,31 @@ top = PRIV(utt_size); while (bot < top) { + int r; i = (bot + top) >> 1; - c = STRCMP_UC_C8(name, PRIV(utt_names) + PRIV(utt)[i].name_offset); - if (c == 0) + r = STRCMP_UC_C8(name, PRIV(utt_names) + PRIV(utt)[i].name_offset); + if (r == 0) { - *dptr = PRIV(utt)[i].value; - return PRIV(utt)[i].type; + *ptypeptr = PRIV(utt)[i].type; + *pdataptr = PRIV(utt)[i].value; + return TRUE; } - if (c > 0) bot = i + 1; else top = i; + if (r > 0) bot = i + 1; else top = i; } *errorcodeptr = ERR47; *ptrptr = ptr; -return -1; +return FALSE; ERROR_RETURN: *errorcodeptr = ERR46; *ptrptr = ptr; -return -1; +return FALSE; } #endif - /************************************************* * Read repeat counts * *************************************************/ @@ -1292,7 +1584,7 @@ int max = -1; /* Read the minimum value and do a paranoid check: a negative value indicates an integer overflow. */ -while (IS_DIGIT(*p)) min = min * 10 + *p++ - CHAR_0; +while (IS_DIGIT(*p)) min = min * 10 + (int)(*p++ - CHAR_0); if (min < 0 || min > 65535) { *errorcodeptr = ERR5; @@ -1307,7 +1599,7 @@ if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else if (*(++p) != CHAR_RIGHT_CURLY_BRACKET) { max = 0; - while(IS_DIGIT(*p)) max = max * 10 + *p++ - CHAR_0; + while(IS_DIGIT(*p)) max = max * 10 + (int)(*p++ - CHAR_0); if (max < 0 || max > 65535) { *errorcodeptr = ERR5; @@ -1331,301 +1623,6 @@ return p; -/************************************************* -* Subroutine for finding forward reference * -*************************************************/ - -/* This recursive function is called only from find_parens() below. The -top-level call starts at the beginning of the pattern. All other calls must -start at a parenthesis. It scans along a pattern's text looking for capturing -subpatterns, and counting them. If it finds a named pattern that matches the -name it is given, it returns its number. Alternatively, if the name is NULL, it -returns when it reaches a given numbered subpattern. Recursion is used to keep -track of subpatterns that reset the capturing group numbers - the (?| feature. - -This function was originally called only from the second pass, in which we know -that if (?< or (?' or (?P< is encountered, the name will be correctly -terminated because that is checked in the first pass. There is now one call to -this function in the first pass, to check for a recursive back reference by -name (so that we can make the whole group atomic). In this case, we need check -only up to the current position in the pattern, and that is still OK because -and previous occurrences will have been checked. To make this work, the test -for "end of pattern" is a check against cd->end_pattern in the main loop, -instead of looking for a binary zero. This means that the special first-pass -call can adjust cd->end_pattern temporarily. (Checks for binary zero while -processing items within the loop are OK, because afterwards the main loop will -terminate.) - -Arguments: - ptrptr address of the current character pointer (updated) - cd compile background data - name name to seek, or NULL if seeking a numbered subpattern - lorn name length, or subpattern number if name is NULL - xmode TRUE if we are in /x mode - utf TRUE if we are in UTF-8 / UTF-16 mode - count pointer to the current capturing subpattern number (updated) - -Returns: the number of the named subpattern, or -1 if not found -*/ - -static int -find_parens_sub(pcre_uchar **ptrptr, compile_data *cd, const pcre_uchar *name, int lorn, - BOOL xmode, BOOL utf, int *count) -{ -pcre_uchar *ptr = *ptrptr; -int start_count = *count; -int hwm_count = start_count; -BOOL dup_parens = FALSE; - -/* If the first character is a parenthesis, check on the type of group we are -dealing with. The very first call may not start with a parenthesis. */ - -if (ptr[0] == CHAR_LEFT_PARENTHESIS) - { - /* Handle specials such as (*SKIP) or (*UTF8) etc. */ - - if (ptr[1] == CHAR_ASTERISK) ptr += 2; - - /* Handle a normal, unnamed capturing parenthesis. */ - - else if (ptr[1] != CHAR_QUESTION_MARK) - { - *count += 1; - if (name == NULL && *count == lorn) return *count; - ptr++; - } - - /* All cases now have (? at the start. Remember when we are in a group - where the parenthesis numbers are duplicated. */ - - else if (ptr[2] == CHAR_VERTICAL_LINE) - { - ptr += 3; - dup_parens = TRUE; - } - - /* Handle comments; all characters are allowed until a ket is reached. */ - - else if (ptr[2] == CHAR_NUMBER_SIGN) - { - for (ptr += 3; *ptr != 0; ptr++) if (*ptr == CHAR_RIGHT_PARENTHESIS) break; - goto FAIL_EXIT; - } - - /* Handle a condition. If it is an assertion, just carry on so that it - is processed as normal. If not, skip to the closing parenthesis of the - condition (there can't be any nested parens). */ - - else if (ptr[2] == CHAR_LEFT_PARENTHESIS) - { - ptr += 2; - if (ptr[1] != CHAR_QUESTION_MARK) - { - while (*ptr != 0 && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; - if (*ptr != 0) ptr++; - } - } - - /* Start with (? but not a condition. */ - - else - { - ptr += 2; - if (*ptr == CHAR_P) ptr++; /* Allow optional P */ - - /* We have to disambiguate (? for named groups */ - - if ((*ptr == CHAR_LESS_THAN_SIGN && ptr[1] != CHAR_EXCLAMATION_MARK && - ptr[1] != CHAR_EQUALS_SIGN) || *ptr == CHAR_APOSTROPHE) - { - int term; - const pcre_uchar *thisname; - *count += 1; - if (name == NULL && *count == lorn) return *count; - term = *ptr++; - if (term == CHAR_LESS_THAN_SIGN) term = CHAR_GREATER_THAN_SIGN; - thisname = ptr; - while (*ptr != term) ptr++; - if (name != NULL && lorn == ptr - thisname && - STRNCMP_UC_UC(name, thisname, lorn) == 0) - return *count; - term++; - } - } - } - -/* Past any initial parenthesis handling, scan for parentheses or vertical -bars. Stop if we get to cd->end_pattern. Note that this is important for the -first-pass call when this value is temporarily adjusted to stop at the current -position. So DO NOT change this to a test for binary zero. */ - -for (; ptr < cd->end_pattern; ptr++) - { - /* Skip over backslashed characters and also entire \Q...\E */ - - if (*ptr == CHAR_BACKSLASH) - { - if (*(++ptr) == 0) goto FAIL_EXIT; - if (*ptr == CHAR_Q) for (;;) - { - while (*(++ptr) != 0 && *ptr != CHAR_BACKSLASH) {}; - if (*ptr == 0) goto FAIL_EXIT; - if (*(++ptr) == CHAR_E) break; - } - continue; - } - - /* Skip over character classes; this logic must be similar to the way they - are handled for real. If the first character is '^', skip it. Also, if the - first few characters (either before or after ^) are \Q\E or \E we skip them - too. This makes for compatibility with Perl. Note the use of STR macros to - encode "Q\\E" so that it works in UTF-8 on EBCDIC platforms. */ - - if (*ptr == CHAR_LEFT_SQUARE_BRACKET) - { - BOOL negate_class = FALSE; - for (;;) - { - if (ptr[1] == CHAR_BACKSLASH) - { - if (ptr[2] == CHAR_E) - ptr+= 2; - else if (STRNCMP_UC_C8(ptr + 2, - STR_Q STR_BACKSLASH STR_E, 3) == 0) - ptr += 4; - else - break; - } - else if (!negate_class && ptr[1] == CHAR_CIRCUMFLEX_ACCENT) - { - negate_class = TRUE; - ptr++; - } - else break; - } - - /* If the next character is ']', it is a data character that must be - skipped, except in JavaScript compatibility mode. */ - - if (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET && - (cd->external_options & PCRE_JAVASCRIPT_COMPAT) == 0) - ptr++; - - while (*(++ptr) != CHAR_RIGHT_SQUARE_BRACKET) - { - if (*ptr == 0) return -1; - if (*ptr == CHAR_BACKSLASH) - { - if (*(++ptr) == 0) goto FAIL_EXIT; - if (*ptr == CHAR_Q) for (;;) - { - while (*(++ptr) != 0 && *ptr != CHAR_BACKSLASH) {}; - if (*ptr == 0) goto FAIL_EXIT; - if (*(++ptr) == CHAR_E) break; - } - continue; - } - } - continue; - } - - /* Skip comments in /x mode */ - - if (xmode && *ptr == CHAR_NUMBER_SIGN) - { - ptr++; - while (*ptr != 0) - { - if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; } - ptr++; -#ifdef SUPPORT_UTF - if (utf) FORWARDCHAR(ptr); -#endif - } - if (*ptr == 0) goto FAIL_EXIT; - continue; - } - - /* Check for the special metacharacters */ - - if (*ptr == CHAR_LEFT_PARENTHESIS) - { - int rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf, count); - if (rc > 0) return rc; - if (*ptr == 0) goto FAIL_EXIT; - } - - else if (*ptr == CHAR_RIGHT_PARENTHESIS) - { - if (dup_parens && *count < hwm_count) *count = hwm_count; - goto FAIL_EXIT; - } - - else if (*ptr == CHAR_VERTICAL_LINE && dup_parens) - { - if (*count > hwm_count) hwm_count = *count; - *count = start_count; - } - } - -FAIL_EXIT: -*ptrptr = ptr; -return -1; -} - - - - -/************************************************* -* Find forward referenced subpattern * -*************************************************/ - -/* This function scans along a pattern's text looking for capturing -subpatterns, and counting them. If it finds a named pattern that matches the -name it is given, it returns its number. Alternatively, if the name is NULL, it -returns when it reaches a given numbered subpattern. This is used for forward -references to subpatterns. We used to be able to start this scan from the -current compiling point, using the current count value from cd->bracount, and -do it all in a single loop, but the addition of the possibility of duplicate -subpattern numbers means that we have to scan from the very start, in order to -take account of such duplicates, and to use a recursive function to keep track -of the different types of group. - -Arguments: - cd compile background data - name name to seek, or NULL if seeking a numbered subpattern - lorn name length, or subpattern number if name is NULL - xmode TRUE if we are in /x mode - utf TRUE if we are in UTF-8 / UTF-16 mode - -Returns: the number of the found subpattern, or -1 if not found -*/ - -static int -find_parens(compile_data *cd, const pcre_uchar *name, int lorn, BOOL xmode, - BOOL utf) -{ -pcre_uchar *ptr = (pcre_uchar *)cd->start_pattern; -int count = 0; -int rc; - -/* If the pattern does not start with an opening parenthesis, the first call -to find_parens_sub() will scan right to the end (if necessary). However, if it -does start with a parenthesis, find_parens_sub() will return when it hits the -matching closing parens. That is why we have to have a loop. */ - -for (;;) - { - rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf, &count); - if (rc > 0 || *ptr++ == 0) break; - } - -return rc; -} - - - - /************************************************* * Find first significant op code * *************************************************/ @@ -1665,9 +1662,9 @@ for (;;) case OP_CALLOUT: case OP_CREF: - case OP_NCREF: + case OP_DNCREF: case OP_RREF: - case OP_NRREF: + case OP_DNRREF: case OP_DEF: code += PRIV(OP_lengths)[*code]; break; @@ -1681,7 +1678,6 @@ for (;;) - /************************************************* * Find the fixed length of a branch * *************************************************/ @@ -1699,7 +1695,7 @@ and doing the check at the end; a flag specifies which mode we are running in. Arguments: code points to the start of the pattern (the bracket) - utf TRUE in UTF-8 / UTF-16 mode + utf TRUE in UTF-8 / UTF-16 / UTF-32 mode atend TRUE if called when the pattern is complete cd the "compile data" structure @@ -1725,7 +1721,7 @@ for (;;) { int d; pcre_uchar *ce, *cs; - register int op = *cc; + register pcre_uchar op = *cc; switch (op) { @@ -1805,13 +1801,13 @@ for (;;) case OP_COMMIT: case OP_CREF: case OP_DEF: + case OP_DNCREF: + case OP_DNRREF: case OP_DOLL: case OP_DOLLM: case OP_EOD: case OP_EODN: case OP_FAIL: - case OP_NCREF: - case OP_NRREF: case OP_NOT_WORD_BOUNDARY: case OP_PRUNE: case OP_REVERSE: @@ -1845,7 +1841,7 @@ for (;;) case OP_EXACTI: case OP_NOTEXACT: case OP_NOTEXACTI: - branchlength += GET2(cc,1); + branchlength += (int)GET2(cc,1); cc += 2 + IMM2_SIZE; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); @@ -1854,7 +1850,8 @@ for (;;) case OP_TYPEEXACT: branchlength += GET2(cc,1); - if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP) cc += 2; + if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP) + cc += 2; cc += 1 + IMM2_SIZE + 1; break; @@ -1889,30 +1886,38 @@ for (;;) /* Check a class for variable quantification */ -#if defined SUPPORT_UTF || defined COMPILE_PCRE16 - case OP_XCLASS: - cc += GET(cc, 1) - PRIV(OP_lengths)[OP_CLASS]; - /* Fall through */ -#endif - case OP_CLASS: case OP_NCLASS: +#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + case OP_XCLASS: + /* The original code caused an unsigned overflow in 64 bit systems, + so now we use a conditional statement. */ + if (op == OP_XCLASS) + cc += GET(cc, 1); + else + cc += PRIV(OP_lengths)[OP_CLASS]; +#else cc += PRIV(OP_lengths)[OP_CLASS]; +#endif switch (*cc) { - case OP_CRPLUS: - case OP_CRMINPLUS: case OP_CRSTAR: case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSPLUS: + case OP_CRPOSQUERY: return -1; case OP_CRRANGE: case OP_CRMINRANGE: + case OP_CRPOSRANGE: if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) return -1; - branchlength += GET2(cc,1); + branchlength += (int)GET2(cc,1); cc += 1 + 2 * IMM2_SIZE; break; @@ -1979,6 +1984,8 @@ for (;;) case OP_QUERYI: case OP_REF: case OP_REFI: + case OP_DNREF: + case OP_DNREFI: case OP_SBRA: case OP_SBRAPOS: case OP_SCBRA: @@ -2015,7 +2022,6 @@ for (;;) - /************************************************* * Scan compiled regex for specific bracket * *************************************************/ @@ -2028,7 +2034,7 @@ length. Arguments: code points to start of expression - utf TRUE in UTF-8 / UTF-16 mode + utf TRUE in UTF-8 / UTF-16 / UTF-32 mode number the required bracket number or negative to find a lookbehind Returns: pointer to the opcode for the bracket, or NULL if not found @@ -2039,7 +2045,7 @@ PRIV(find_bracket)(const pcre_uchar *code, BOOL utf, int number) { for (;;) { - register int c = *code; + register pcre_uchar c = *code; if (c == OP_END) return NULL; @@ -2062,7 +2068,7 @@ for (;;) else if (c == OP_CBRA || c == OP_SCBRA || c == OP_CBRAPOS || c == OP_SCBRAPOS) { - int n = GET2(code, 1+LINK_SIZE); + int n = (int)GET2(code, 1+LINK_SIZE); if (n == number) return (pcre_uchar *)code; code += PRIV(OP_lengths)[c]; } @@ -2092,16 +2098,13 @@ for (;;) case OP_TYPEMINUPTO: case OP_TYPEEXACT: case OP_TYPEPOSUPTO: - if (code[1 + IMM2_SIZE] == OP_PROP - || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2; + if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) + code += 2; break; case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: - code += code[1]; - break; - case OP_THEN_ARG: code += code[1]; break; @@ -2115,7 +2118,7 @@ for (;;) a multi-byte character. The length in the table is a minimum, so we have to arrange to skip the extra bytes. */ -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) switch(c) { case OP_CHAR: @@ -2167,7 +2170,7 @@ instance of OP_RECURSE. Arguments: code points to start of expression - utf TRUE in UTF-8 / UTF-16 mode + utf TRUE in UTF-8 / UTF-16 / UTF-32 mode Returns: pointer to the opcode for OP_RECURSE, or NULL if not found */ @@ -2177,7 +2180,7 @@ find_recurse(const pcre_uchar *code, BOOL utf) { for (;;) { - register int c = *code; + register pcre_uchar c = *code; if (c == OP_END) return NULL; if (c == OP_RECURSE) return code; @@ -2212,16 +2215,13 @@ for (;;) case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEEXACT: - if (code[1 + IMM2_SIZE] == OP_PROP - || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2; + if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) + code += 2; break; case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: - code += code[1]; - break; - case OP_THEN_ARG: code += code[1]; break; @@ -2235,7 +2235,7 @@ for (;;) by a multi-byte character. The length in the table is a minimum, so we have to arrange to skip the extra bytes. */ -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) switch(c) { case OP_CHAR: @@ -2321,17 +2321,25 @@ bracket whose current branch will already have been scanned. Arguments: code points to start of search endcode points to where to stop - utf TRUE if in UTF-8 / UTF-16 mode + utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode cd contains pointers to tables etc. + recurses chain of recurse_check to catch mutual recursion Returns: TRUE if what is matched could be empty */ +typedef struct recurse_check { + struct recurse_check *prev; + const pcre_uchar *group; +} recurse_check; + static BOOL could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode, - BOOL utf, compile_data *cd) + BOOL utf, compile_data *cd, recurse_check *recurses) { -register int c; +register pcre_uchar c; +recurse_check this_recurse; + for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); code < endcode; code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE)) @@ -2359,25 +2367,50 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); if (c == OP_RECURSE) { - const pcre_uchar *scode; + const pcre_uchar *scode = cd->start_code + GET(code, 1); BOOL empty_branch; - /* Test for forward reference */ + /* Test for forward reference or uncompleted reference. This is disabled + when called to scan a completed pattern by setting cd->start_workspace to + NULL. */ - for (scode = cd->start_workspace; scode < cd->hwm; scode += LINK_SIZE) - if (GET(scode, 0) == code + 1 - cd->start_code) return TRUE; + if (cd->start_workspace != NULL) + { + const pcre_uchar *tcode; + for (tcode = cd->start_workspace; tcode < cd->hwm; tcode += LINK_SIZE) + if ((int)GET(tcode, 0) == (int)(code + 1 - cd->start_code)) return TRUE; + if (GET(scode, 1) == 0) return TRUE; /* Unclosed */ + } - /* Not a forward reference, test for completed backward reference */ + /* If we are scanning a completed pattern, there are no forward references + and all groups are complete. We need to detect whether this is a recursive + call, as otherwise there will be an infinite loop. If it is a recursion, + just skip over it. Simple recursions are easily detected. For mutual + recursions we keep a chain on the stack. */ + + else + { + recurse_check *r = recurses; + const pcre_uchar *endgroup = scode; + + do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT); + if (code >= scode && code <= endgroup) continue; /* Simple recursion */ + + for (r = recurses; r != NULL; r = r->prev) + if (r->group == scode) break; + if (r != NULL) continue; /* Mutual recursion */ + } + + /* Completed reference; scan the referenced group, remembering it on the + stack chain to detect mutual recursions. */ empty_branch = FALSE; - scode = cd->start_code + GET(code, 1); - if (GET(scode, 1) == 0) return TRUE; /* Unclosed */ - - /* Completed backwards reference */ + this_recurse.prev = recurses; + this_recurse.group = scode; do { - if (could_be_empty_branch(scode, endcode, utf, cd)) + if (could_be_empty_branch(scode, endcode, utf, cd, &this_recurse)) { empty_branch = TRUE; break; @@ -2433,7 +2466,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); empty_branch = FALSE; do { - if (!empty_branch && could_be_empty_branch(code, endcode, utf, cd)) + if (!empty_branch && could_be_empty_branch(code, endcode, utf, cd, NULL)) empty_branch = TRUE; code += GET(code, 1); } @@ -2475,15 +2508,19 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSQUERY: break; default: /* Non-repeat => class must match */ case OP_CRPLUS: /* These repeats aren't empty */ case OP_CRMINPLUS: + case OP_CRPOSPLUS: return FALSE; case OP_CRRANGE: case OP_CRMINRANGE: + case OP_CRPOSRANGE: if (GET2(ccode, 1) > 0) return FALSE; /* Minimum > 0 */ break; } @@ -2491,34 +2528,57 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); /* Opcodes that must match a character */ + case OP_ANY: + case OP_ALLANY: + case OP_ANYBYTE: + case OP_PROP: case OP_NOTPROP: + case OP_ANYNL: + + case OP_NOT_HSPACE: + case OP_HSPACE: + case OP_NOT_VSPACE: + case OP_VSPACE: case OP_EXTUNI: + case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: - case OP_ANY: - case OP_ALLANY: - case OP_ANYBYTE: + case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: + case OP_PLUS: + case OP_PLUSI: case OP_MINPLUS: - case OP_POSPLUS: - case OP_EXACT: + case OP_MINPLUSI: + case OP_NOTPLUS: + case OP_NOTPLUSI: case OP_NOTMINPLUS: + case OP_NOTMINPLUSI: + + case OP_POSPLUS: + case OP_POSPLUSI: case OP_NOTPOSPLUS: + case OP_NOTPOSPLUSI: + + case OP_EXACT: + case OP_EXACTI: case OP_NOTEXACT: + case OP_NOTEXACTI: + case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEPOSPLUS: case OP_TYPEEXACT: + return FALSE; /* These are going to continue, as they may be empty, but we have to @@ -2538,8 +2598,8 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEPOSUPTO: - if (code[1 + IMM2_SIZE] == OP_PROP - || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2; + if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) + code += 2; break; /* End of branch */ @@ -2552,30 +2612,58 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); return TRUE; /* In UTF-8 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, POSQUERY, UPTO, - MINUPTO, and POSUPTO may be followed by a multibyte character */ + MINUPTO, and POSUPTO and their caseless and negative versions may be + followed by a multibyte character. */ -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 case OP_STAR: case OP_STARI: + case OP_NOTSTAR: + case OP_NOTSTARI: + case OP_MINSTAR: case OP_MINSTARI: + case OP_NOTMINSTAR: + case OP_NOTMINSTARI: + case OP_POSSTAR: case OP_POSSTARI: + case OP_NOTPOSSTAR: + case OP_NOTPOSSTARI: + case OP_QUERY: case OP_QUERYI: + case OP_NOTQUERY: + case OP_NOTQUERYI: + case OP_MINQUERY: case OP_MINQUERYI: + case OP_NOTMINQUERY: + case OP_NOTMINQUERYI: + case OP_POSQUERY: case OP_POSQUERYI: + case OP_NOTPOSQUERY: + case OP_NOTPOSQUERYI: + if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]); break; case OP_UPTO: case OP_UPTOI: + case OP_NOTUPTO: + case OP_NOTUPTOI: + case OP_MINUPTO: case OP_MINUPTOI: + case OP_NOTMINUPTO: + case OP_NOTMINUPTOI: + case OP_POSUPTO: case OP_POSUPTOI: + case OP_NOTPOSUPTO: + case OP_NOTPOSUPTOI: + if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]); break; #endif @@ -2586,9 +2674,6 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: - code += code[1]; - break; - case OP_THEN_ARG: code += code[1]; break; @@ -2620,7 +2705,7 @@ Arguments: code points to start of the recursion endcode points to where to stop (current RECURSE item) bcptr points to the chain of current (unclosed) branch starts - utf TRUE if in UTF-8 / UTF-16 mode + utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode cd pointers to tables etc Returns: TRUE if what is matched could be empty @@ -2632,7 +2717,7 @@ could_be_empty(const pcre_uchar *code, const pcre_uchar *endcode, { while (bcptr != NULL && bcptr->current_branch >= code) { - if (!could_be_empty_branch(bcptr->current_branch, endcode, utf, cd)) + if (!could_be_empty_branch(bcptr->current_branch, endcode, utf, cd, NULL)) return FALSE; bcptr = bcptr->outer; } @@ -2641,6 +2726,1072 @@ return TRUE; +/************************************************* +* Base opcode of repeated opcodes * +*************************************************/ + +/* Returns the base opcode for repeated single character type opcodes. If the +opcode is not a repeated character type, it returns with the original value. + +Arguments: c opcode +Returns: base opcode for the type +*/ + +static pcre_uchar +get_repeat_base(pcre_uchar c) +{ +return (c > OP_TYPEPOSUPTO)? c : + (c >= OP_TYPESTAR)? OP_TYPESTAR : + (c >= OP_NOTSTARI)? OP_NOTSTARI : + (c >= OP_NOTSTAR)? OP_NOTSTAR : + (c >= OP_STARI)? OP_STARI : + OP_STAR; +} + + + +#ifdef SUPPORT_UCP +/************************************************* +* Check a character and a property * +*************************************************/ + +/* This function is called by check_auto_possessive() when a property item +is adjacent to a fixed character. + +Arguments: + c the character + ptype the property type + pdata the data for the type + negated TRUE if it's a negated property (\P or \p{^) + +Returns: TRUE if auto-possessifying is OK +*/ + +static BOOL +check_char_prop(pcre_uint32 c, unsigned int ptype, unsigned int pdata, + BOOL negated) +{ +const pcre_uint32 *p; +const ucd_record *prop = GET_UCD(c); + +switch(ptype) + { + case PT_LAMP: + return (prop->chartype == ucp_Lu || + prop->chartype == ucp_Ll || + prop->chartype == ucp_Lt) == negated; + + case PT_GC: + return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated; + + case PT_PC: + return (pdata == prop->chartype) == negated; + + case PT_SC: + return (pdata == prop->script) == negated; + + /* These are specials */ + + case PT_ALNUM: + return (PRIV(ucp_gentype)[prop->chartype] == ucp_L || + PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated; + + /* Perl space used to exclude VT, but from Perl 5.18 it is included, which + means that Perl space and POSIX space are now identical. PCRE was changed + at release 8.34. */ + + case PT_SPACE: /* Perl space */ + case PT_PXSPACE: /* POSIX space */ + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + return negated; + + default: + return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == negated; + } + break; /* Control never reaches here */ + + case PT_WORD: + return (PRIV(ucp_gentype)[prop->chartype] == ucp_L || + PRIV(ucp_gentype)[prop->chartype] == ucp_N || + c == CHAR_UNDERSCORE) == negated; + + case PT_CLIST: + p = PRIV(ucd_caseless_sets) + prop->caseset; + for (;;) + { + if (c < *p) return !negated; + if (c == *p++) return negated; + } + break; /* Control never reaches here */ + } + +return FALSE; +} +#endif /* SUPPORT_UCP */ + + + +/************************************************* +* Fill the character property list * +*************************************************/ + +/* Checks whether the code points to an opcode that can take part in auto- +possessification, and if so, fills a list with its properties. + +Arguments: + code points to start of expression + utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode + fcc points to case-flipping table + list points to output list + list[0] will be filled with the opcode + list[1] will be non-zero if this opcode + can match an empty character string + list[2..7] depends on the opcode + +Returns: points to the start of the next opcode if *code is accepted + NULL if *code is not accepted +*/ + +static const pcre_uchar * +get_chr_property_list(const pcre_uchar *code, BOOL utf, + const pcre_uint8 *fcc, pcre_uint32 *list) +{ +pcre_uchar c = *code; +pcre_uchar base; +const pcre_uchar *end; +pcre_uint32 chr; + +#ifdef SUPPORT_UCP +pcre_uint32 *clist_dest; +const pcre_uint32 *clist_src; +#else +utf = utf; /* Suppress "unused parameter" compiler warning */ +#endif + +list[0] = c; +list[1] = FALSE; +code++; + +if (c >= OP_STAR && c <= OP_TYPEPOSUPTO) + { + base = get_repeat_base(c); + c -= (base - OP_STAR); + + if (c == OP_UPTO || c == OP_MINUPTO || c == OP_EXACT || c == OP_POSUPTO) + code += IMM2_SIZE; + + list[1] = (c != OP_PLUS && c != OP_MINPLUS && c != OP_EXACT && c != OP_POSPLUS); + + switch(base) + { + case OP_STAR: + list[0] = OP_CHAR; + break; + + case OP_STARI: + list[0] = OP_CHARI; + break; + + case OP_NOTSTAR: + list[0] = OP_NOT; + break; + + case OP_NOTSTARI: + list[0] = OP_NOTI; + break; + + case OP_TYPESTAR: + list[0] = *code; + code++; + break; + } + c = list[0]; + } + +switch(c) + { + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + case OP_ANY: + case OP_ALLANY: + case OP_ANYNL: + case OP_NOT_HSPACE: + case OP_HSPACE: + case OP_NOT_VSPACE: + case OP_VSPACE: + case OP_EXTUNI: + case OP_EODN: + case OP_EOD: + case OP_DOLL: + case OP_DOLLM: + return code; + + case OP_CHAR: + case OP_NOT: + GETCHARINCTEST(chr, code); + list[2] = chr; + list[3] = NOTACHAR; + return code; + + case OP_CHARI: + case OP_NOTI: + list[0] = (c == OP_CHARI) ? OP_CHAR : OP_NOT; + GETCHARINCTEST(chr, code); + list[2] = chr; + +#ifdef SUPPORT_UCP + if (chr < 128 || (chr < 256 && !utf)) + list[3] = fcc[chr]; + else + list[3] = UCD_OTHERCASE(chr); +#elif defined SUPPORT_UTF || !defined COMPILE_PCRE8 + list[3] = (chr < 256) ? fcc[chr] : chr; +#else + list[3] = fcc[chr]; +#endif + + /* The othercase might be the same value. */ + + if (chr == list[3]) + list[3] = NOTACHAR; + else + list[4] = NOTACHAR; + return code; + +#ifdef SUPPORT_UCP + case OP_PROP: + case OP_NOTPROP: + if (code[0] != PT_CLIST) + { + list[2] = code[0]; + list[3] = code[1]; + return code + 2; + } + + /* Convert only if we have enough space. */ + + clist_src = PRIV(ucd_caseless_sets) + code[1]; + clist_dest = list + 2; + code += 2; + + do { + if (clist_dest >= list + 8) + { + /* Early return if there is not enough space. This should never + happen, since all clists are shorter than 5 character now. */ + list[2] = code[0]; + list[3] = code[1]; + return code; + } + *clist_dest++ = *clist_src; + } + while(*clist_src++ != NOTACHAR); + + /* All characters are stored. The terminating NOTACHAR + is copied form the clist itself. */ + + list[0] = (c == OP_PROP) ? OP_CHAR : OP_NOT; + return code; +#endif + + case OP_NCLASS: + case OP_CLASS: +#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + case OP_XCLASS: + if (c == OP_XCLASS) + end = code + GET(code, 0) - 1; + else +#endif + end = code + 32 / sizeof(pcre_uchar); + + switch(*end) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRQUERY: + case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSQUERY: + list[1] = TRUE; + end++; + break; + + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRPOSPLUS: + end++; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + case OP_CRPOSRANGE: + list[1] = (GET2(end, 1) == 0); + end += 1 + 2 * IMM2_SIZE; + break; + } + list[2] = end - code; + return end; + } +return NULL; /* Opcode not accepted */ +} + + + +/************************************************* +* Scan further character sets for match * +*************************************************/ + +/* Checks whether the base and the current opcode have a common character, in +which case the base cannot be possessified. + +Arguments: + code points to the byte code + utf TRUE in UTF-8 / UTF-16 / UTF-32 mode + cd static compile data + base_list the data list of the base opcode + +Returns: TRUE if the auto-possessification is possible +*/ + +static BOOL +compare_opcodes(const pcre_uchar *code, BOOL utf, const compile_data *cd, + const pcre_uint32 *base_list, const pcre_uchar *base_end) +{ +pcre_uchar c; +pcre_uint32 list[8]; +const pcre_uint32 *chr_ptr; +const pcre_uint32 *ochr_ptr; +const pcre_uint32 *list_ptr; +const pcre_uchar *next_code; +const pcre_uint8 *class_bitset; +const pcre_uint32 *set1, *set2, *set_end; +pcre_uint32 chr; +BOOL accepted, invert_bits; + +/* Note: the base_list[1] contains whether the current opcode has greedy +(represented by a non-zero value) quantifier. This is a different from +other character type lists, which stores here that the character iterator +matches to an empty string (also represented by a non-zero value). */ + +for(;;) + { + /* All operations move the code pointer forward. + Therefore infinite recursions are not possible. */ + + c = *code; + + /* Skip over callouts */ + + if (c == OP_CALLOUT) + { + code += PRIV(OP_lengths)[c]; + continue; + } + + if (c == OP_ALT) + { + do code += GET(code, 1); while (*code == OP_ALT); + c = *code; + } + + switch(c) + { + case OP_END: + case OP_KETRPOS: + /* TRUE only in greedy case. The non-greedy case could be replaced by + an OP_EXACT, but it is probably not worth it. (And note that OP_EXACT + uses more memory, which we cannot get at this stage.) */ + + return base_list[1] != 0; + + case OP_KET: + /* If the bracket is capturing, and referenced by an OP_RECURSE, or + it is an atomic sub-pattern (assert, once, etc.) the non-greedy case + cannot be converted to a possessive form. */ + + if (base_list[1] == 0) return FALSE; + + switch(*(code - GET(code, 1))) + { + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + case OP_ONCE: + case OP_ONCE_NC: + /* Atomic sub-patterns and assertions can always auto-possessify their + last iterator. */ + return TRUE; + } + + code += PRIV(OP_lengths)[c]; + continue; + + case OP_ONCE: + case OP_ONCE_NC: + case OP_BRA: + case OP_CBRA: + next_code = code + GET(code, 1); + code += PRIV(OP_lengths)[c]; + + while (*next_code == OP_ALT) + { + if (!compare_opcodes(code, utf, cd, base_list, base_end)) return FALSE; + code = next_code + 1 + LINK_SIZE; + next_code += GET(next_code, 1); + } + continue; + + case OP_BRAZERO: + case OP_BRAMINZERO: + + next_code = code + 1; + if (*next_code != OP_BRA && *next_code != OP_CBRA + && *next_code != OP_ONCE && *next_code != OP_ONCE_NC) return FALSE; + + do next_code += GET(next_code, 1); while (*next_code == OP_ALT); + + /* The bracket content will be checked by the + OP_BRA/OP_CBRA case above. */ + next_code += 1 + LINK_SIZE; + if (!compare_opcodes(next_code, utf, cd, base_list, base_end)) + return FALSE; + + code += PRIV(OP_lengths)[c]; + continue; + } + + /* Check for a supported opcode, and load its properties. */ + + code = get_chr_property_list(code, utf, cd->fcc, list); + if (code == NULL) return FALSE; /* Unsupported */ + + /* If either opcode is a small character list, set pointers for comparing + characters from that list with another list, or with a property. */ + + if (base_list[0] == OP_CHAR) + { + chr_ptr = base_list + 2; + list_ptr = list; + } + else if (list[0] == OP_CHAR) + { + chr_ptr = list + 2; + list_ptr = base_list; + } + + /* Character bitsets can also be compared to certain opcodes. */ + + else if (base_list[0] == OP_CLASS || list[0] == OP_CLASS +#ifdef COMPILE_PCRE8 + /* In 8 bit, non-UTF mode, OP_CLASS and OP_NCLASS are the same. */ + || (!utf && (base_list[0] == OP_NCLASS || list[0] == OP_NCLASS)) +#endif + ) + { +#ifdef COMPILE_PCRE8 + if (base_list[0] == OP_CLASS || (!utf && base_list[0] == OP_NCLASS)) +#else + if (base_list[0] == OP_CLASS) +#endif + { + set1 = (pcre_uint32 *)(base_end - base_list[2]); + list_ptr = list; + } + else + { + set1 = (pcre_uint32 *)(code - list[2]); + list_ptr = base_list; + } + + invert_bits = FALSE; + switch(list_ptr[0]) + { + case OP_CLASS: + case OP_NCLASS: + set2 = (pcre_uint32 *) + ((list_ptr == list ? code : base_end) - list_ptr[2]); + break; + + /* OP_XCLASS cannot be supported here, because its bitset + is not necessarily complete. E.g: [a-\0x{200}] is stored + as a character range, and the appropriate bits are not set. */ + + case OP_NOT_DIGIT: + invert_bits = TRUE; + /* Fall through */ + case OP_DIGIT: + set2 = (pcre_uint32 *)(cd->cbits + cbit_digit); + break; + + case OP_NOT_WHITESPACE: + invert_bits = TRUE; + /* Fall through */ + case OP_WHITESPACE: + set2 = (pcre_uint32 *)(cd->cbits + cbit_space); + break; + + case OP_NOT_WORDCHAR: + invert_bits = TRUE; + /* Fall through */ + case OP_WORDCHAR: + set2 = (pcre_uint32 *)(cd->cbits + cbit_word); + break; + + default: + return FALSE; + } + + /* Compare 4 bytes to improve speed. */ + set_end = set1 + (32 / 4); + if (invert_bits) + { + do + { + if ((*set1++ & ~(*set2++)) != 0) return FALSE; + } + while (set1 < set_end); + } + else + { + do + { + if ((*set1++ & *set2++) != 0) return FALSE; + } + while (set1 < set_end); + } + + if (list[1] == 0) return TRUE; + /* Might be an empty repeat. */ + continue; + } + + /* Some property combinations also acceptable. Unicode property opcodes are + processed specially; the rest can be handled with a lookup table. */ + + else + { + pcre_uint32 leftop, rightop; + + leftop = base_list[0]; + rightop = list[0]; + +#ifdef SUPPORT_UCP + accepted = FALSE; /* Always set in non-unicode case. */ + if (leftop == OP_PROP || leftop == OP_NOTPROP) + { + if (rightop == OP_EOD) + accepted = TRUE; + else if (rightop == OP_PROP || rightop == OP_NOTPROP) + { + int n; + const pcre_uint8 *p; + BOOL same = leftop == rightop; + BOOL lisprop = leftop == OP_PROP; + BOOL risprop = rightop == OP_PROP; + BOOL bothprop = lisprop && risprop; + + /* There's a table that specifies how each combination is to be + processed: + 0 Always return FALSE (never auto-possessify) + 1 Character groups are distinct (possessify if both are OP_PROP) + 2 Check character categories in the same group (general or particular) + 3 Return TRUE if the two opcodes are not the same + ... see comments below + */ + + n = propposstab[base_list[2]][list[2]]; + switch(n) + { + case 0: break; + case 1: accepted = bothprop; break; + case 2: accepted = (base_list[3] == list[3]) != same; break; + case 3: accepted = !same; break; + + case 4: /* Left general category, right particular category */ + accepted = risprop && catposstab[base_list[3]][list[3]] == same; + break; + + case 5: /* Right general category, left particular category */ + accepted = lisprop && catposstab[list[3]][base_list[3]] == same; + break; + + /* This code is logically tricky. Think hard before fiddling with it. + The posspropstab table has four entries per row. Each row relates to + one of PCRE's special properties such as ALNUM or SPACE or WORD. + Only WORD actually needs all four entries, but using repeats for the + others means they can all use the same code below. + + The first two entries in each row are Unicode general categories, and + apply always, because all the characters they include are part of the + PCRE character set. The third and fourth entries are a general and a + particular category, respectively, that include one or more relevant + characters. One or the other is used, depending on whether the check + is for a general or a particular category. However, in both cases the + category contains more characters than the specials that are defined + for the property being tested against. Therefore, it cannot be used + in a NOTPROP case. + + Example: the row for WORD contains ucp_L, ucp_N, ucp_P, ucp_Po. + Underscore is covered by ucp_P or ucp_Po. */ + + case 6: /* Left alphanum vs right general category */ + case 7: /* Left space vs right general category */ + case 8: /* Left word vs right general category */ + p = posspropstab[n-6]; + accepted = risprop && lisprop == + (list[3] != p[0] && + list[3] != p[1] && + (list[3] != p[2] || !lisprop)); + break; + + case 9: /* Right alphanum vs left general category */ + case 10: /* Right space vs left general category */ + case 11: /* Right word vs left general category */ + p = posspropstab[n-9]; + accepted = lisprop && risprop == + (base_list[3] != p[0] && + base_list[3] != p[1] && + (base_list[3] != p[2] || !risprop)); + break; + + case 12: /* Left alphanum vs right particular category */ + case 13: /* Left space vs right particular category */ + case 14: /* Left word vs right particular category */ + p = posspropstab[n-12]; + accepted = risprop && lisprop == + (catposstab[p[0]][list[3]] && + catposstab[p[1]][list[3]] && + (list[3] != p[3] || !lisprop)); + break; + + case 15: /* Right alphanum vs left particular category */ + case 16: /* Right space vs left particular category */ + case 17: /* Right word vs left particular category */ + p = posspropstab[n-15]; + accepted = lisprop && risprop == + (catposstab[p[0]][base_list[3]] && + catposstab[p[1]][base_list[3]] && + (base_list[3] != p[3] || !risprop)); + break; + } + } + } + + else +#endif /* SUPPORT_UCP */ + + accepted = leftop >= FIRST_AUTOTAB_OP && leftop <= LAST_AUTOTAB_LEFT_OP && + rightop >= FIRST_AUTOTAB_OP && rightop <= LAST_AUTOTAB_RIGHT_OP && + autoposstab[leftop - FIRST_AUTOTAB_OP][rightop - FIRST_AUTOTAB_OP]; + + if (!accepted) + return FALSE; + + if (list[1] == 0) return TRUE; + /* Might be an empty repeat. */ + continue; + } + + /* Control reaches here only if one of the items is a small character list. + All characters are checked against the other side. */ + + do + { + chr = *chr_ptr; + + switch(list_ptr[0]) + { + case OP_CHAR: + ochr_ptr = list_ptr + 2; + do + { + if (chr == *ochr_ptr) return FALSE; + ochr_ptr++; + } + while(*ochr_ptr != NOTACHAR); + break; + + case OP_NOT: + ochr_ptr = list_ptr + 2; + do + { + if (chr == *ochr_ptr) + break; + ochr_ptr++; + } + while(*ochr_ptr != NOTACHAR); + if (*ochr_ptr == NOTACHAR) return FALSE; /* Not found */ + break; + + /* Note that OP_DIGIT etc. are generated only when PCRE_UCP is *not* + set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */ + + case OP_DIGIT: + if (chr < 256 && (cd->ctypes[chr] & ctype_digit) != 0) return FALSE; + break; + + case OP_NOT_DIGIT: + if (chr > 255 || (cd->ctypes[chr] & ctype_digit) == 0) return FALSE; + break; + + case OP_WHITESPACE: + if (chr < 256 && (cd->ctypes[chr] & ctype_space) != 0) return FALSE; + break; + + case OP_NOT_WHITESPACE: + if (chr > 255 || (cd->ctypes[chr] & ctype_space) == 0) return FALSE; + break; + + case OP_WORDCHAR: + if (chr < 255 && (cd->ctypes[chr] & ctype_word) != 0) return FALSE; + break; + + case OP_NOT_WORDCHAR: + if (chr > 255 || (cd->ctypes[chr] & ctype_word) == 0) return FALSE; + break; + + case OP_HSPACE: + switch(chr) + { + HSPACE_CASES: return FALSE; + default: break; + } + break; + + case OP_NOT_HSPACE: + switch(chr) + { + HSPACE_CASES: break; + default: return FALSE; + } + break; + + case OP_ANYNL: + case OP_VSPACE: + switch(chr) + { + VSPACE_CASES: return FALSE; + default: break; + } + break; + + case OP_NOT_VSPACE: + switch(chr) + { + VSPACE_CASES: break; + default: return FALSE; + } + break; + + case OP_DOLL: + case OP_EODN: + switch (chr) + { + case CHAR_CR: + case CHAR_LF: + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC + case 0x2028: + case 0x2029: +#endif /* Not EBCDIC */ + return FALSE; + } + break; + + case OP_EOD: /* Can always possessify before \z */ + break; + +#ifdef SUPPORT_UCP + case OP_PROP: + case OP_NOTPROP: + if (!check_char_prop(chr, list_ptr[2], list_ptr[3], + list_ptr[0] == OP_NOTPROP)) + return FALSE; + break; +#endif + + case OP_NCLASS: + if (chr > 255) return FALSE; + /* Fall through */ + + case OP_CLASS: + if (chr > 255) break; + class_bitset = (pcre_uint8 *) + ((list_ptr == list ? code : base_end) - list_ptr[2]); + if ((class_bitset[chr >> 3] & (1 << (chr & 7))) != 0) return FALSE; + break; + +#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + case OP_XCLASS: + if (PRIV(xclass)(chr, (list_ptr == list ? code : base_end) - + list_ptr[2] + LINK_SIZE, utf)) return FALSE; + break; +#endif + + default: + return FALSE; + } + + chr_ptr++; + } + while(*chr_ptr != NOTACHAR); + + /* At least one character must be matched from this opcode. */ + + if (list[1] == 0) return TRUE; + } + +return FALSE; +} + + + +/************************************************* +* Scan compiled regex for auto-possession * +*************************************************/ + +/* Replaces single character iterations with their possessive alternatives +if appropriate. This function modifies the compiled opcode! + +Arguments: + code points to start of the byte code + utf TRUE in UTF-8 / UTF-16 / UTF-32 mode + cd static compile data + +Returns: nothing +*/ + +static void +auto_possessify(pcre_uchar *code, BOOL utf, const compile_data *cd) +{ +register pcre_uchar c; +const pcre_uchar *end; +pcre_uchar *repeat_opcode; +pcre_uint32 list[8]; + +for (;;) + { + c = *code; + + if (c >= OP_STAR && c <= OP_TYPEPOSUPTO) + { + c -= get_repeat_base(c) - OP_STAR; + end = (c <= OP_MINUPTO) ? + get_chr_property_list(code, utf, cd->fcc, list) : NULL; + list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO; + + if (end != NULL && compare_opcodes(end, utf, cd, list, end)) + { + switch(c) + { + case OP_STAR: + *code += OP_POSSTAR - OP_STAR; + break; + + case OP_MINSTAR: + *code += OP_POSSTAR - OP_MINSTAR; + break; + + case OP_PLUS: + *code += OP_POSPLUS - OP_PLUS; + break; + + case OP_MINPLUS: + *code += OP_POSPLUS - OP_MINPLUS; + break; + + case OP_QUERY: + *code += OP_POSQUERY - OP_QUERY; + break; + + case OP_MINQUERY: + *code += OP_POSQUERY - OP_MINQUERY; + break; + + case OP_UPTO: + *code += OP_POSUPTO - OP_UPTO; + break; + + case OP_MINUPTO: + *code += OP_MINUPTO - OP_UPTO; + break; + } + } + c = *code; + } + else if (c == OP_CLASS || c == OP_NCLASS || c == OP_XCLASS) + { +#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + if (c == OP_XCLASS) + repeat_opcode = code + GET(code, 1); + else +#endif + repeat_opcode = code + 1 + (32 / sizeof(pcre_uchar)); + + c = *repeat_opcode; + if (c >= OP_CRSTAR && c <= OP_CRMINRANGE) + { + /* end must not be NULL. */ + end = get_chr_property_list(code, utf, cd->fcc, list); + + list[1] = (c & 1) == 0; + + if (compare_opcodes(end, utf, cd, list, end)) + { + switch (c) + { + case OP_CRSTAR: + case OP_CRMINSTAR: + *repeat_opcode = OP_CRPOSSTAR; + break; + + case OP_CRPLUS: + case OP_CRMINPLUS: + *repeat_opcode = OP_CRPOSPLUS; + break; + + case OP_CRQUERY: + case OP_CRMINQUERY: + *repeat_opcode = OP_CRPOSQUERY; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + *repeat_opcode = OP_CRPOSRANGE; + break; + } + } + } + c = *code; + } + + switch(c) + { + case OP_END: + return; + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEEXACT: + case OP_TYPEPOSUPTO: + if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) + code += 2; + break; + +#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + case OP_XCLASS: + code += GET(code, 1); + break; +#endif + + case OP_MARK: + case OP_PRUNE_ARG: + case OP_SKIP_ARG: + case OP_THEN_ARG: + code += code[1]; + break; + } + + /* Add in the fixed length from the table */ + + code += PRIV(OP_lengths)[c]; + + /* In UTF-8 mode, opcodes that are followed by a character may be followed by + a multi-byte character. The length in the table is a minimum, so we have to + arrange to skip the extra bytes. */ + +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 + if (utf) switch(c) + { + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + case OP_STAR: + case OP_MINSTAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_QUERY: + case OP_MINQUERY: + case OP_UPTO: + case OP_MINUPTO: + case OP_EXACT: + case OP_POSSTAR: + case OP_POSPLUS: + case OP_POSQUERY: + case OP_POSUPTO: + case OP_STARI: + case OP_MINSTARI: + case OP_PLUSI: + case OP_MINPLUSI: + case OP_QUERYI: + case OP_MINQUERYI: + case OP_UPTOI: + case OP_MINUPTOI: + case OP_EXACTI: + case OP_POSSTARI: + case OP_POSPLUSI: + case OP_POSQUERYI: + case OP_POSUPTOI: + case OP_NOTSTAR: + case OP_NOTMINSTAR: + case OP_NOTPLUS: + case OP_NOTMINPLUS: + case OP_NOTQUERY: + case OP_NOTMINQUERY: + case OP_NOTUPTO: + case OP_NOTMINUPTO: + case OP_NOTEXACT: + case OP_NOTPOSSTAR: + case OP_NOTPOSPLUS: + case OP_NOTPOSQUERY: + case OP_NOTPOSUPTO: + case OP_NOTSTARI: + case OP_NOTMINSTARI: + case OP_NOTPLUSI: + case OP_NOTMINPLUSI: + case OP_NOTQUERYI: + case OP_NOTMINQUERYI: + case OP_NOTUPTOI: + case OP_NOTMINUPTOI: + case OP_NOTEXACTI: + case OP_NOTPOSSTARI: + case OP_NOTPOSPLUSI: + case OP_NOTPOSQUERYI: + case OP_NOTPOSUPTOI: + if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); + break; + } +#else + (void)(utf); /* Keep compiler happy by referencing function argument */ +#endif + } +} + + + /************************************************* * Check for POSIX class syntax * *************************************************/ @@ -2662,7 +3813,7 @@ 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 that not diagnosing bad classes when Perl does, +"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. @@ -2686,9 +3837,9 @@ Returns: TRUE or FALSE static BOOL check_posix_syntax(const pcre_uchar *ptr, const pcre_uchar **endptr) { -int terminator; /* Don't combine these lines; the Solaris cc */ +pcre_uchar terminator; /* Don't combine these lines; the Solaris cc */ terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ -for (++ptr; *ptr != 0; ptr++) +for (++ptr; *ptr != CHAR_NULL; ptr++) { if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) ptr++; @@ -2735,7 +3886,7 @@ register int yield = 0; while (posix_name_lengths[yield] != 0) { if (len == posix_name_lengths[yield] && - STRNCMP_UC_C8(ptr, pn, len) == 0) return yield; + STRNCMP_UC_C8(ptr, pn, (unsigned int)len) == 0) return yield; pn += posix_name_lengths[yield] + 1; yield++; } @@ -2767,7 +3918,7 @@ value in the reference (which is a group number). Arguments: group points to the start of the group adjust the amount by which the group is to be moved - utf TRUE in UTF-8 / UTF-16 mode + utf TRUE in UTF-8 / UTF-16 / UTF-32 mode cd contains pointers to tables etc. save_hwm the hwm forward reference pointer at the start of the group @@ -2790,7 +3941,7 @@ while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL) for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE) { - offset = GET(hc, 0); + offset = (int)GET(hc, 0); if (cd->start_code + offset == ptr + 1) { PUT(hc, 0, offset + adjust); @@ -2803,7 +3954,7 @@ while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL) if (hc >= cd->hwm) { - offset = GET(ptr, 1); + offset = (int)GET(ptr, 1); if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust); } @@ -2871,9 +4022,10 @@ PUT(previous_callout, 2 + LINK_SIZE, length); *************************************************/ /* This function is passed the start and end of a class range, in UTF-8 mode -with UCP support. It searches up the characters, looking for internal ranges of +with UCP support. It searches up the characters, looking for ranges of characters in the "other" case. Each call returns the next one, updating the -start address. +start address. A character with multiple other cases is returned on its own +with a special return value. Arguments: cptr points to starting character value; updated @@ -2881,19 +4033,34 @@ Arguments: ocptr where to put start of othercase range odptr where to put end of othercase range -Yield: TRUE when range returned; FALSE when no more +Yield: -1 when no more + 0 when a range is returned + >0 the CASESET offset for char with multiple other cases + in this case, ocptr contains the original */ -static BOOL -get_othercase_range(unsigned int *cptr, unsigned int d, unsigned int *ocptr, - unsigned int *odptr) +static int +get_othercase_range(pcre_uint32 *cptr, pcre_uint32 d, pcre_uint32 *ocptr, + pcre_uint32 *odptr) { -unsigned int c, othercase, next; +pcre_uint32 c, othercase, next; +unsigned int co; + +/* Find the first character that has an other case. If it has multiple other +cases, return its case offset value. */ for (c = *cptr; c <= d; c++) - { if ((othercase = UCD_OTHERCASE(c)) != c) break; } + { + if ((co = UCD_CASESET(c)) != 0) + { + *ocptr = c++; /* Character that has the set */ + *cptr = c; /* Rest of input range */ + return (int)co; + } + if ((othercase = UCD_OTHERCASE(c)) != c) break; + } -if (c > d) return FALSE; +if (c > d) return -1; /* Reached end of range */ *ocptr = othercase; next = othercase + 1; @@ -2904,498 +4071,248 @@ for (++c; c <= d; c++) next++; } -*odptr = next - 1; -*cptr = c; - -return TRUE; -} - - - -/************************************************* -* Check a character and a property * -*************************************************/ - -/* This function is called by check_auto_possessive() when a property item -is adjacent to a fixed character. - -Arguments: - c the character - ptype the property type - pdata the data for the type - negated TRUE if it's a negated property (\P or \p{^) - -Returns: TRUE if auto-possessifying is OK -*/ - -static BOOL -check_char_prop(int c, int ptype, int pdata, BOOL negated) -{ -const ucd_record *prop = GET_UCD(c); -switch(ptype) - { - case PT_LAMP: - return (prop->chartype == ucp_Lu || - prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt) == negated; - - case PT_GC: - return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated; - - case PT_PC: - return (pdata == prop->chartype) == negated; - - case PT_SC: - return (pdata == prop->script) == negated; - - /* These are specials */ - - case PT_ALNUM: - return (PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated; - - case PT_SPACE: /* Perl space */ - return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR) - == negated; - - case PT_PXSPACE: /* POSIX space */ - return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_VT || - c == CHAR_FF || c == CHAR_CR) - == negated; - - case PT_WORD: - return (PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N || - c == CHAR_UNDERSCORE) == negated; - } -return FALSE; +*odptr = next - 1; /* End of othercase range */ +*cptr = c; /* Rest of input range */ +return 0; } #endif /* SUPPORT_UCP */ /************************************************* -* Check if auto-possessifying is possible * +* Add a character or range to a class * *************************************************/ -/* This function is called for unlimited repeats of certain items, to see -whether the next thing could possibly match the repeated item. If not, it makes -sense to automatically possessify the repeated item. +/* This function packages up the logic of adding a character or range of +characters to a class. The character values in the arguments will be within the +valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is +mutually recursive with the function immediately below. Arguments: - previous pointer to the repeated opcode - utf TRUE in UTF-8 / UTF-16 mode - ptr next character in pattern - options options bits + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word cd contains pointers to tables etc. + start start of range character + end end of range character -Returns: TRUE if possessifying is wanted +Returns: the number of < 256 characters added + the pointer to extra data is updated */ -static BOOL -check_auto_possessive(const pcre_uchar *previous, BOOL utf, - const pcre_uchar *ptr, int options, compile_data *cd) +static int +add_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options, + compile_data *cd, pcre_uint32 start, pcre_uint32 end) { -pcre_int32 c, next; -int op_code = *previous++; +pcre_uint32 c; +int n8 = 0; -/* Skip whitespace and comments in extended mode */ +/* If caseless matching is required, scan the range and process alternate +cases. In Unicode, there are 8-bit characters that have alternate cases that +are greater than 255 and vice-versa. Sometimes we can just extend the original +range. */ -if ((options & PCRE_EXTENDED) != 0) +if ((options & PCRE_CASELESS) != 0) { - for (;;) - { - while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_space) != 0) ptr++; - if (*ptr == CHAR_NUMBER_SIGN) - { - ptr++; - while (*ptr != 0) - { - if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } - ptr++; -#ifdef SUPPORT_UTF - if (utf) FORWARDCHAR(ptr); -#endif - } - } - else break; - } - } - -/* If the next item is one that we can handle, get its value. A non-negative -value is a character, a negative value is an escape value. */ - -if (*ptr == CHAR_BACKSLASH) - { - int temperrorcode = 0; - next = check_escape(&ptr, &temperrorcode, cd->bracount, options, FALSE); - if (temperrorcode != 0) return FALSE; - ptr++; /* Point after the escape sequence */ - } -else if (!MAX_255(*ptr) || (cd->ctypes[*ptr] & ctype_meta) == 0) - { -#ifdef SUPPORT_UTF - if (utf) { GETCHARINC(next, ptr); } else -#endif - next = *ptr++; - } -else return FALSE; - -/* Skip whitespace and comments in extended mode */ - -if ((options & PCRE_EXTENDED) != 0) - { - for (;;) - { - while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_space) != 0) ptr++; - if (*ptr == CHAR_NUMBER_SIGN) - { - ptr++; - while (*ptr != 0) - { - if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } - ptr++; -#ifdef SUPPORT_UTF - if (utf) FORWARDCHAR(ptr); -#endif - } - } - else break; - } - } - -/* If the next thing is itself optional, we have to give up. */ - -if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MARK || - STRNCMP_UC_C8(ptr, STR_LEFT_CURLY_BRACKET STR_0 STR_COMMA, 3) == 0) - return FALSE; - -/* Now compare the next item with the previous opcode. First, handle cases when -the next item is a character. */ - -if (next >= 0) switch(op_code) - { - case OP_CHAR: -#ifdef SUPPORT_UTF - GETCHARTEST(c, previous); -#else - c = *previous; -#endif - return c != next; - - /* For CHARI (caseless character) we must check the other case. If we have - Unicode property support, we can use it to test the other case of - high-valued characters. */ - - case OP_CHARI: -#ifdef SUPPORT_UTF - GETCHARTEST(c, previous); -#else - c = *previous; -#endif - if (c == next) return FALSE; -#ifdef SUPPORT_UTF - if (utf) - { - unsigned int othercase; - if (next < 128) othercase = cd->fcc[next]; else #ifdef SUPPORT_UCP - othercase = UCD_OTHERCASE((unsigned int)next); -#else - othercase = NOTACHAR; + if ((options & PCRE_UTF8) != 0) + { + int rc; + pcre_uint32 oc, od; + + options &= ~PCRE_CASELESS; /* Remove for recursive calls */ + c = start; + + while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0) + { + /* Handle a single character that has more than one other case. */ + + if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cd, + PRIV(ucd_caseless_sets) + rc, oc); + + /* Do nothing if the other case range is within the original range. */ + + else if (oc >= start && od <= end) continue; + + /* Extend the original range if there is overlap, noting that if oc < c, we + can't have od > end because a subrange is always shorter than the basic + range. Otherwise, use a recursive call to add the additional range. */ + + else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */ + else if (od > end && oc <= end + 1) end = od; /* Extend upwards */ + else n8 += add_to_class(classbits, uchardptr, options, cd, oc, od); + } + } + else +#endif /* SUPPORT_UCP */ + + /* Not UTF-mode, or no UCP */ + + for (c = start; c <= end && c < 256; c++) + { + SETBIT(classbits, cd->fcc[c]); + n8++; + } + } + +/* Now handle the original range. Adjust the final value according to the bit +length - this means that the same lists of (e.g.) horizontal spaces can be used +in all cases. */ + +#if defined COMPILE_PCRE8 +#ifdef SUPPORT_UTF + if ((options & PCRE_UTF8) == 0) #endif - return (unsigned int)c != othercase; + if (end > 0xff) end = 0xff; + +#elif defined COMPILE_PCRE16 +#ifdef SUPPORT_UTF + if ((options & PCRE_UTF16) == 0) +#endif + if (end > 0xffff) end = 0xffff; + +#endif /* COMPILE_PCRE[8|16] */ + +/* If all characters are less than 256, use the bit map. Otherwise use extra +data. */ + +if (end < 0x100) + { + for (c = start; c <= end; c++) + { + n8++; + SETBIT(classbits, c); + } + } + +else + { + pcre_uchar *uchardata = *uchardptr; + +#ifdef SUPPORT_UTF + if ((options & PCRE_UTF8) != 0) /* All UTFs use the same flag bit */ + { + if (start < end) + { + *uchardata++ = XCL_RANGE; + uchardata += PRIV(ord2utf)(start, uchardata); + uchardata += PRIV(ord2utf)(end, uchardata); + } + else if (start == end) + { + *uchardata++ = XCL_SINGLE; + uchardata += PRIV(ord2utf)(start, uchardata); + } } else #endif /* SUPPORT_UTF */ - return (c != TABLE_GET((unsigned int)next, cd->fcc, next)); /* Non-UTF-8 mode */ - case OP_NOT: -#ifdef SUPPORT_UTF - GETCHARTEST(c, previous); + /* Without UTF support, character values are constrained by the bit length, + and can only be > 256 for 16-bit and 32-bit libraries. */ + +#ifdef COMPILE_PCRE8 + {} #else - c = *previous; -#endif - return c == next; - - case OP_NOTI: -#ifdef SUPPORT_UTF - GETCHARTEST(c, previous); -#else - c = *previous; -#endif - if (c == next) return TRUE; -#ifdef SUPPORT_UTF - if (utf) + if (start < end) { - unsigned int othercase; - if (next < 128) othercase = cd->fcc[next]; else -#ifdef SUPPORT_UCP - othercase = UCD_OTHERCASE((unsigned int)next); -#else - othercase = NOTACHAR; -#endif - return (unsigned int)c == othercase; + *uchardata++ = XCL_RANGE; + *uchardata++ = start; + *uchardata++ = end; } - else -#endif /* SUPPORT_UTF */ - return (c == TABLE_GET((unsigned int)next, cd->fcc, next)); /* Non-UTF-8 mode */ - - /* Note that OP_DIGIT etc. are generated only when PCRE_UCP is *not* set. - When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */ - - case OP_DIGIT: - return next > 255 || (cd->ctypes[next] & ctype_digit) == 0; - - case OP_NOT_DIGIT: - return next <= 255 && (cd->ctypes[next] & ctype_digit) != 0; - - case OP_WHITESPACE: - return next > 255 || (cd->ctypes[next] & ctype_space) == 0; - - case OP_NOT_WHITESPACE: - return next <= 255 && (cd->ctypes[next] & ctype_space) != 0; - - case OP_WORDCHAR: - return next > 255 || (cd->ctypes[next] & ctype_word) == 0; - - case OP_NOT_WORDCHAR: - return next <= 255 && (cd->ctypes[next] & ctype_word) != 0; - - case OP_HSPACE: - case OP_NOT_HSPACE: - switch(next) + else if (start == end) { - case 0x09: - case 0x20: - case 0xa0: - case 0x1680: - case 0x180e: - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - case 0x2004: - case 0x2005: - case 0x2006: - case 0x2007: - case 0x2008: - case 0x2009: - case 0x200A: - case 0x202f: - case 0x205f: - case 0x3000: - return op_code == OP_NOT_HSPACE; - default: - return op_code != OP_NOT_HSPACE; + *uchardata++ = XCL_SINGLE; + *uchardata++ = start; } - - case OP_ANYNL: - case OP_VSPACE: - case OP_NOT_VSPACE: - switch(next) - { - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x85: - case 0x2028: - case 0x2029: - return op_code == OP_NOT_VSPACE; - default: - return op_code != OP_NOT_VSPACE; - } - -#ifdef SUPPORT_UCP - case OP_PROP: - return check_char_prop(next, previous[0], previous[1], FALSE); - - case OP_NOTPROP: - return check_char_prop(next, previous[0], previous[1], TRUE); #endif - default: - return FALSE; + *uchardptr = uchardata; /* Updata extra data pointer */ } +return n8; /* Number of 8-bit characters */ +} -/* Handle the case when the next item is \d, \s, etc. Note that when PCRE_UCP -is set, \d turns into ESC_du rather than ESC_d, etc., so ESC_d etc. are -generated only when PCRE_UCP is *not* set, that is, when only ASCII -characteristics are recognized. Similarly, the opcodes OP_DIGIT etc. are -replaced by OP_PROP codes when PCRE_UCP is set. */ -switch(op_code) + + +/************************************************* +* Add a list of characters to a class * +*************************************************/ + +/* This function is used for adding a list of case-equivalent characters to a +class, and also for adding a list of horizontal or vertical whitespace. If the +list is in order (which it should be), ranges of characters are detected and +handled appropriately. This function is mutually recursive with the function +above. + +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cd contains pointers to tables etc. + p points to row of 32-bit values, terminated by NOTACHAR + except character to omit; this is used when adding lists of + case-equivalent characters to avoid including the one we + already know about + +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ + +static int +add_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options, + compile_data *cd, const pcre_uint32 *p, unsigned int except) +{ +int n8 = 0; +while (p[0] < NOTACHAR) { - case OP_CHAR: - case OP_CHARI: -#ifdef SUPPORT_UTF - GETCHARTEST(c, previous); -#else - c = *previous; -#endif - switch(-next) + int n = 0; + if (p[0] != except) { - case ESC_d: - return c > 255 || (cd->ctypes[c] & ctype_digit) == 0; - - case ESC_D: - return c <= 255 && (cd->ctypes[c] & ctype_digit) != 0; - - case ESC_s: - return c > 255 || (cd->ctypes[c] & ctype_space) == 0; - - case ESC_S: - return c <= 255 && (cd->ctypes[c] & ctype_space) != 0; - - case ESC_w: - return c > 255 || (cd->ctypes[c] & ctype_word) == 0; - - case ESC_W: - return c <= 255 && (cd->ctypes[c] & ctype_word) != 0; - - case ESC_h: - case ESC_H: - switch(c) - { - case 0x09: - case 0x20: - case 0xa0: - case 0x1680: - case 0x180e: - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - case 0x2004: - case 0x2005: - case 0x2006: - case 0x2007: - case 0x2008: - case 0x2009: - case 0x200A: - case 0x202f: - case 0x205f: - case 0x3000: - return -next != ESC_h; - default: - return -next == ESC_h; - } - - case ESC_v: - case ESC_V: - switch(c) - { - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x85: - case 0x2028: - case 0x2029: - return -next != ESC_v; - default: - return -next == ESC_v; - } - - /* When PCRE_UCP is set, these values get generated for \d etc. Find - their substitutions and process them. The result will always be either - -ESC_p or -ESC_P. Then fall through to process those values. */ - -#ifdef SUPPORT_UCP - case ESC_du: - case ESC_DU: - case ESC_wu: - case ESC_WU: - case ESC_su: - case ESC_SU: - { - int temperrorcode = 0; - ptr = substitutes[-next - ESC_DU]; - next = check_escape(&ptr, &temperrorcode, 0, options, FALSE); - if (temperrorcode != 0) return FALSE; - ptr++; /* For compatibility */ - } - /* Fall through */ - - case ESC_p: - case ESC_P: - { - int ptype, pdata, errorcodeptr; - BOOL negated; - - ptr--; /* Make ptr point at the p or P */ - ptype = get_ucp(&ptr, &negated, &pdata, &errorcodeptr); - if (ptype < 0) return FALSE; - ptr++; /* Point past the final curly ket */ - - /* If the property item is optional, we have to give up. (When generated - from \d etc by PCRE_UCP, this test will have been applied much earlier, - to the original \d etc. At this point, ptr will point to a zero byte. */ - - if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MARK || - STRNCMP_UC_C8(ptr, STR_LEFT_CURLY_BRACKET STR_0 STR_COMMA, 3) == 0) - return FALSE; - - /* Do the property check. */ - - return check_char_prop(c, ptype, pdata, (next == -ESC_P) != negated); - } -#endif - - default: - return FALSE; + while(p[n+1] == p[0] + n + 1) n++; + n8 += add_to_class(classbits, uchardptr, options, cd, p[0], p[n]); } - - /* In principle, support for Unicode properties should be integrated here as - well. It means re-organizing the above code so as to get hold of the property - values before switching on the op-code. However, I wonder how many patterns - combine ASCII \d etc with Unicode properties? (Note that if PCRE_UCP is set, - these op-codes are never generated.) */ - - case OP_DIGIT: - return next == -ESC_D || next == -ESC_s || next == -ESC_W || - next == -ESC_h || next == -ESC_v || next == -ESC_R; - - case OP_NOT_DIGIT: - return next == -ESC_d; - - case OP_WHITESPACE: - return next == -ESC_S || next == -ESC_d || next == -ESC_w; - - case OP_NOT_WHITESPACE: - return next == -ESC_s || next == -ESC_h || next == -ESC_v || next == -ESC_R; - - case OP_HSPACE: - return next == -ESC_S || next == -ESC_H || next == -ESC_d || - next == -ESC_w || next == -ESC_v || next == -ESC_R; - - case OP_NOT_HSPACE: - return next == -ESC_h; - - /* Can't have \S in here because VT matches \S (Perl anomaly) */ - case OP_ANYNL: - case OP_VSPACE: - return next == -ESC_V || next == -ESC_d || next == -ESC_w; - - case OP_NOT_VSPACE: - return next == -ESC_v || next == -ESC_R; - - case OP_WORDCHAR: - return next == -ESC_W || next == -ESC_s || next == -ESC_h || - next == -ESC_v || next == -ESC_R; - - case OP_NOT_WORDCHAR: - return next == -ESC_w || next == -ESC_d; - - default: - return FALSE; + p += n + 1; } +return n8; +} -/* Control does not reach here */ + + +/************************************************* +* Add characters not in a list to a class * +*************************************************/ + +/* This function is used for adding the complement of a list of horizontal or +vertical whitespace to a class. The list must be in order. + +Arguments: + classbits the bit map for characters < 256 + uchardptr points to the pointer for extra data + options the options word + cd contains pointers to tables etc. + p points to row of 32-bit values, terminated by NOTACHAR + +Returns: the number of < 256 characters added + the pointer to extra data is updated +*/ + +static int +add_not_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, + int options, compile_data *cd, const pcre_uint32 *p) +{ +BOOL utf = (options & PCRE_UTF8) != 0; +int n8 = 0; +if (p[0] > 0) + n8 += add_to_class(classbits, uchardptr, options, cd, 0, p[0] - 1); +while (p[0] < NOTACHAR) + { + while (p[1] == p[0] + 1) p++; + n8 += add_to_class(classbits, uchardptr, options, cd, p[0] + 1, + (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1); + p++; + } +return n8; } @@ -3411,39 +4328,46 @@ to find out the amount of memory needed, as well as during the real compile phase. The value of lengthptr distinguishes the two phases. Arguments: - optionsptr pointer to the option bits - codeptr points to the pointer to the current code point - ptrptr points to the current pattern pointer - errorcodeptr points to error code variable - firstcharptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) - reqcharptr set to the last literal character required, else < 0 - bcptr points to current branch chain - cond_depth conditional nesting depth - cd contains pointers to tables etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase + optionsptr pointer to the option bits + codeptr points to the pointer to the current code point + ptrptr points to the current pattern pointer + errorcodeptr points to error code variable + firstcharptr place to put the first required character + firstcharflagsptr place to put the first character flags, or a negative number + reqcharptr place to put the last required character + reqcharflagsptr place to put the last required character flags, or a negative number + bcptr points to current branch chain + cond_depth conditional nesting depth + cd contains pointers to tables etc. + lengthptr NULL during the real compile phase + points to length accumulator during pre-compile phase -Returns: TRUE on success - FALSE, with *errorcodeptr set non-zero on error +Returns: TRUE on success + FALSE, with *errorcodeptr set non-zero on error */ static BOOL compile_branch(int *optionsptr, pcre_uchar **codeptr, - const pcre_uchar **ptrptr, int *errorcodeptr, pcre_int32 *firstcharptr, - pcre_int32 *reqcharptr, branch_chain *bcptr, int cond_depth, + const pcre_uchar **ptrptr, int *errorcodeptr, + pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr, + pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr, + branch_chain *bcptr, int cond_depth, compile_data *cd, int *lengthptr) { int repeat_type, op_type; int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ int bravalue = 0; int greedy_default, greedy_non_default; -pcre_int32 firstchar, reqchar; -pcre_int32 zeroreqchar, zerofirstchar; +pcre_uint32 firstchar, reqchar; +pcre_int32 firstcharflags, reqcharflags; +pcre_uint32 zeroreqchar, zerofirstchar; +pcre_int32 zeroreqcharflags, zerofirstcharflags; pcre_int32 req_caseopt, reqvary, tempreqvary; int options = *optionsptr; /* May change dynamically */ int after_manual_callout = 0; int length_prevgroup = 0; -register int c; +register pcre_uint32 c; +int escape; register pcre_uchar *code = *codeptr; pcre_uchar *last_code = code; pcre_uchar *orig_code = code; @@ -3463,18 +4387,23 @@ must not do this for other options (e.g. PCRE_EXTENDED) because they may change dynamically as we process the pattern. */ #ifdef SUPPORT_UTF -/* PCRE_UTF16 has the same value as PCRE_UTF8. */ +/* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */ BOOL utf = (options & PCRE_UTF8) != 0; +#ifndef COMPILE_PCRE32 pcre_uchar utf_chars[6]; +#endif #else BOOL utf = FALSE; #endif -/* Helper variables for OP_XCLASS opcode (for characters > 255). */ +/* Helper variables for OP_XCLASS opcode (for characters > 255). We define +class_uchardata always so that it can be passed to add_to_class() always, +though it will not be used in non-UTF 8-bit cases. This avoids having to supply +alternative calls for the different cases. */ +pcre_uchar *class_uchardata; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 BOOL xclass; -pcre_uchar *class_uchardata; pcre_uchar *class_uchardata_base; #endif @@ -3497,7 +4426,8 @@ to take the zero repeat into account. This is implemented by setting them to zerofirstbyte and zeroreqchar when such a repeat is encountered. The individual item types that can be repeated set these backoff variables appropriately. */ -firstchar = reqchar = zerofirstchar = zeroreqchar = REQ_UNSET; +firstchar = reqchar = zerofirstchar = zeroreqchar = 0; +firstcharflags = reqcharflags = zerofirstcharflags = zeroreqcharflags = REQ_UNSET; /* The variable req_caseopt contains either the REQ_CASELESS value or zero, according to the current setting of the caseless flag. The @@ -3518,16 +4448,17 @@ for (;; ptr++) BOOL is_recurse; BOOL reset_bracount; int class_has_8bitchar; - int class_single_char; + int class_one_char; int newoptions; int recno; int refsign; int skipbytes; - int subreqchar; - int subfirstchar; + pcre_uint32 subreqchar, subfirstchar; + pcre_int32 subreqcharflags, subfirstcharflags; int terminator; - int mclength; - int tempbracount; + unsigned int mclength; + unsigned int tempbracount; + pcre_uint32 ec; pcre_uchar mcbuffer[8]; /* Get next character in the pattern */ @@ -3537,7 +4468,7 @@ for (;; ptr++) /* If we are at the end of a nested substitution, revert to the outer level string. Nesting only happens one level deep. */ - if (c == 0 && nestptr != NULL) + if (c == CHAR_NULL && nestptr != NULL) { ptr = nestptr; nestptr = NULL; @@ -3612,7 +4543,7 @@ for (;; ptr++) /* If in \Q...\E, check for the end; if not, we have a literal */ - if (inescq && c != 0) + if (inescq && c != CHAR_NULL) { if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) { @@ -3635,16 +4566,45 @@ for (;; ptr++) } goto NORMAL_CHAR; } + /* Control does not reach here. */ } - /* Fill in length of a previous callout, except when the next thing is - a quantifier. */ + /* In extended mode, skip white space and comments. We need a loop in order + to check for more white space and more comments after a comment. */ + + if ((options & PCRE_EXTENDED) != 0) + { + for (;;) + { + while (MAX_255(c) && (cd->ctypes[c] & ctype_space) != 0) c = *(++ptr); + if (c != CHAR_NUMBER_SIGN) break; + ptr++; + while (*ptr != CHAR_NULL) + { + if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ + { /* IS_NEWLINE sets cd->nllen. */ + ptr += cd->nllen; + break; + } + ptr++; +#ifdef SUPPORT_UTF + if (utf) FORWARDCHAR(ptr); +#endif + } + c = *ptr; /* Either NULL or the char after a newline */ + } + } + + /* See if the next thing is a quantifier. */ is_quantifier = c == CHAR_ASTERISK || c == CHAR_PLUS || c == CHAR_QUESTION_MARK || (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1)); - if (!is_quantifier && previous_callout != NULL && + /* Fill in length of a previous callout, except when the next thing is a + quantifier or when processing a property substitution string in UCP mode. */ + + if (!is_quantifier && previous_callout != NULL && nestptr == NULL && after_manual_callout-- <= 0) { if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ @@ -3652,45 +4612,27 @@ for (;; ptr++) previous_callout = NULL; } - /* In extended mode, skip white space and comments. */ + /* Create auto callout, except for quantifiers, or while processing property + strings that are substituted for \w etc in UCP mode. */ - if ((options & PCRE_EXTENDED) != 0) - { - if (MAX_255(*ptr) && (cd->ctypes[c] & ctype_space) != 0) continue; - if (c == CHAR_NUMBER_SIGN) - { - ptr++; - while (*ptr != 0) - { - if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; } - ptr++; -#ifdef SUPPORT_UTF - if (utf) FORWARDCHAR(ptr); -#endif - } - if (*ptr != 0) continue; - - /* Else fall through to handle end of string */ - c = 0; - } - } - - /* No auto callout for quantifiers. */ - - if ((options & PCRE_AUTO_CALLOUT) != 0 && !is_quantifier) + if ((options & PCRE_AUTO_CALLOUT) != 0 && !is_quantifier && nestptr == NULL) { previous_callout = code; code = auto_callout(code, ptr, cd); } + /* Process the next pattern item. */ + switch(c) { /* ===================================================================*/ - case 0: /* The branch terminates at string end */ + case CHAR_NULL: /* The branch terminates at string end */ case CHAR_VERTICAL_LINE: /* or | or ) */ case CHAR_RIGHT_PARENTHESIS: *firstcharptr = firstchar; + *firstcharflagsptr = firstcharflags; *reqcharptr = reqchar; + *reqcharflagsptr = reqcharflags; *codeptr = code; *ptrptr = ptr; if (lengthptr != NULL) @@ -3714,7 +4656,7 @@ for (;; ptr++) previous = NULL; if ((options & PCRE_MULTILINE) != 0) { - if (firstchar == REQ_UNSET) firstchar = REQ_NONE; + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; *code++ = OP_CIRCM; } else *code++ = OP_CIRC; @@ -3729,9 +4671,11 @@ for (;; ptr++) repeats. The value of reqchar doesn't change either. */ case CHAR_DOT: - if (firstchar == REQ_UNSET) firstchar = REQ_NONE; + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; zerofirstchar = firstchar; + zerofirstcharflags = firstcharflags; zeroreqchar = reqchar; + zeroreqcharflags = reqcharflags; previous = code; *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY; break; @@ -3760,7 +4704,29 @@ for (;; ptr++) } goto NORMAL_CHAR; + /* In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is + used for "start of word" and "end of word". As these are otherwise illegal + sequences, we don't break anything by recognizing them. They are replaced + by \b(?=\w) and \b(?<=\w) respectively. Sequences like [a[:<:]] are + erroneous and are handled by the normal code below. */ + case CHAR_LEFT_SQUARE_BRACKET: + if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0) + { + nestptr = ptr + 7; + ptr = sub_start_of_word - 1; + continue; + } + + if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0) + { + nestptr = ptr + 7; + ptr = sub_end_of_word - 1; + continue; + } + + /* Handle a real character class. */ + previous = code; /* PCRE supports POSIX class stuff inside a class. Perl gives an error if @@ -3805,8 +4771,9 @@ for (;; ptr++) (cd->external_options & PCRE_JAVASCRIPT_COMPAT) != 0) { *code++ = negate_class? OP_ALLANY : OP_FAIL; - if (firstchar == REQ_UNSET) firstchar = REQ_NONE; + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; zerofirstchar = firstchar; + zerofirstcharflags = firstcharflags; break; } @@ -3816,32 +4783,32 @@ for (;; ptr++) should_flip_negation = FALSE; - /* For optimization purposes, we track some properties of the class. - class_has_8bitchar will be non-zero, if the class contains at least one - < 256 character. class_single_char will be 1 if the class contains only - a single character. */ + /* For optimization purposes, we track some properties of the class: + class_has_8bitchar will be non-zero if the class contains at least one < + 256 character; class_one_char will be 1 if the class contains just one + character. */ class_has_8bitchar = 0; - class_single_char = 0; + class_one_char = 0; /* Initialize the 32-char bit map to all zeros. We build the map in a - temporary bit of memory, in case the class contains only 1 character (less - than 256), because in that case the compiled code doesn't use the bit map. - */ + temporary bit of memory, in case the class contains fewer than two + 8-bit characters because in that case the compiled code doesn't use the bit + map. */ memset(classbits, 0, 32 * sizeof(pcre_uint8)); #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 - xclass = FALSE; /* No chars >= 256 */ - class_uchardata = code + LINK_SIZE + 2; /* For UTF-8 items */ - class_uchardata_base = class_uchardata; /* For resetting in pass 1 */ + xclass = FALSE; + class_uchardata = code + LINK_SIZE + 2; /* For XCLASS items */ + class_uchardata_base = class_uchardata; /* Save the start */ #endif /* Process characters until ] is reached. By writing this as a "do" it means that an initial ] is taken as a data character. At the start of the loop, c contains the first byte of the character. */ - if (c != 0) do + if (c != CHAR_NULL) do { const pcre_uchar *oldptr; @@ -3856,10 +4823,12 @@ for (;; ptr++) /* In the pre-compile phase, accumulate the length of any extra data and reset the pointer. This is so that very large classes that contain a zillion > 255 characters no longer overwrite the work space - (which is on the stack). */ + (which is on the stack). We have to remember that there was XCLASS data, + however. */ - if (lengthptr != NULL) + if (lengthptr != NULL && class_uchardata > class_uchardata_base) { + xclass = TRUE; *lengthptr += class_uchardata - class_uchardata_base; class_uchardata = class_uchardata_base; } @@ -3922,24 +4891,58 @@ for (;; ptr++) posix_class = 0; /* When PCRE_UCP is set, some of the POSIX classes are converted to - different escape sequences that use Unicode properties. */ + different escape sequences that use Unicode properties \p or \P. Others + that are not available via \p or \P generate XCL_PROP/XCL_NOTPROP + directly. */ #ifdef SUPPORT_UCP if ((options & PCRE_UCP) != 0) { + unsigned int ptype = 0; int pc = posix_class + ((local_negate)? POSIX_SUBSIZE/2 : 0); + + /* The posix_substitutes table specifies which POSIX classes can be + converted to \p or \P items. */ + if (posix_substitutes[pc] != NULL) { nestptr = tempptr + 1; ptr = posix_substitutes[pc] - 1; continue; } + + /* There are three other classes that generate special property calls + that are recognized only in an XCLASS. */ + + else switch(posix_class) + { + case PC_GRAPH: + ptype = PT_PXGRAPH; + /* Fall through */ + case PC_PRINT: + if (ptype == 0) ptype = PT_PXPRINT; + /* Fall through */ + case PC_PUNCT: + if (ptype == 0) ptype = PT_PXPUNCT; + *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP; + *class_uchardata++ = ptype; + *class_uchardata++ = 0; + ptr = tempptr + 1; + continue; + + /* For all other POSIX classes, no special action is taken in UCP + mode. Fall through to the non_UCP case. */ + + default: + break; + } } #endif - /* In the non-UCP case, we build the bit map for the POSIX class in a - chunk of local store because we may be adding and subtracting from it, - and we don't want to subtract bits that may be in the main map already. - At the end we or the result into the bit map that is being built. */ + /* In the non-UCP case, or when UCP makes no difference, we build the + bit map for the POSIX class in a chunk of local store because we may be + adding and subtracting from it, and we don't want to subtract bits that + may be in the main map already. At the end we or the result into the + bit map that is being built. */ posix_class *= 3; @@ -3961,7 +4964,7 @@ for (;; ptr++) for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset]; } - /* Not see if we need to remove any special characters. An option + /* Now see if we need to remove any special characters. An option value of 1 removes vertical space and 2 removes underscore. */ if (tabopt < 0) tabopt = -tabopt; @@ -3977,10 +4980,10 @@ for (;; ptr++) for (c = 0; c < 32; c++) classbits[c] |= pbits[c]; ptr = tempptr + 1; - /* Every class contains at least one < 256 characters. */ + /* Every class contains at least one < 256 character. */ class_has_8bitchar = 1; /* Every class contains at least two characters. */ - class_single_char = 2; + class_one_char = 2; continue; /* End of POSIX syntax handling */ } @@ -3988,23 +4991,24 @@ for (;; ptr++) of the specials, which just set a flag. The sequence \b is a special case. Inside a class (and only there) it is treated as backspace. We assume that other escapes have more than one character in them, so - speculatively set both class_has_8bitchar and class_single_char bigger + speculatively set both class_has_8bitchar and class_one_char bigger than one. Unrecognized escapes fall through and are either treated as literal characters (by default), or are faulted if PCRE_EXTRA is set. */ if (c == CHAR_BACKSLASH) { - c = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE); + escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options, + TRUE); if (*errorcodeptr != 0) goto FAILED; - - if (-c == ESC_b) c = CHAR_BS; /* \b is backspace in a class */ - else if (-c == ESC_N) /* \N is not supported in a class */ + if (escape == 0) c = ec; + else if (escape == ESC_b) c = CHAR_BS; /* \b is backspace in a class */ + else if (escape == ESC_N) /* \N is not supported in a class */ { *errorcodeptr = ERR71; goto FAILED; } - else if (-c == ESC_Q) /* Handle start of quoted string */ + else if (escape == ESC_Q) /* Handle start of quoted string */ { if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) { @@ -4013,17 +5017,17 @@ for (;; ptr++) else inescq = TRUE; continue; } - else if (-c == ESC_E) continue; /* Ignore orphan \E */ + else if (escape == ESC_E) continue; /* Ignore orphan \E */ - if (c < 0) + else { register const pcre_uint8 *cbits = cd->cbits; /* Every class contains at least two < 256 characters. */ class_has_8bitchar++; /* Every class contains at least two characters. */ - class_single_char += 2; + class_one_char += 2; - switch (-c) + switch (escape) { #ifdef SUPPORT_UCP case ESC_du: /* These are the values given for \d etc */ @@ -4033,7 +5037,7 @@ for (;; ptr++) case ESC_su: /* of the default ASCII testing. */ case ESC_SU: nestptr = ptr; - ptr = substitutes[-c - ESC_DU] - 1; /* Just before substitute */ + ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ class_has_8bitchar--; /* Undo! */ continue; #endif @@ -4055,196 +5059,42 @@ for (;; ptr++) for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word]; continue; - /* Perl 5.004 onwards omits VT from \s, but we must preserve it - if it was previously set by something earlier in the character - class. */ + /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl + 5.18. Before PCRE 8.34, we had to preserve the VT bit if it was + previously set by something earlier in the character class. + Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so + we could just adjust the appropriate bit. From PCRE 8.34 we no + longer treat \s and \S specially. */ case ESC_s: - classbits[0] |= cbits[cbit_space]; - classbits[1] |= cbits[cbit_space+1] & ~0x08; - for (c = 2; c < 32; c++) classbits[c] |= cbits[c+cbit_space]; + for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space]; continue; case ESC_S: should_flip_negation = TRUE; for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space]; - classbits[1] |= 0x08; /* Perl 5.004 onwards omits VT from \s */ continue; + /* The rest apply in both UCP and non-UCP cases. */ + case ESC_h: - SETBIT(classbits, 0x09); /* VT */ - SETBIT(classbits, 0x20); /* SPACE */ - SETBIT(classbits, 0xa0); /* NSBP */ -#ifndef COMPILE_PCRE8 - xclass = TRUE; - *class_uchardata++ = XCL_SINGLE; - *class_uchardata++ = 0x1680; - *class_uchardata++ = XCL_SINGLE; - *class_uchardata++ = 0x180e; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x2000; - *class_uchardata++ = 0x200a; - *class_uchardata++ = XCL_SINGLE; - *class_uchardata++ = 0x202f; - *class_uchardata++ = XCL_SINGLE; - *class_uchardata++ = 0x205f; - *class_uchardata++ = XCL_SINGLE; - *class_uchardata++ = 0x3000; -#elif defined SUPPORT_UTF - if (utf) - { - xclass = TRUE; - *class_uchardata++ = XCL_SINGLE; - class_uchardata += PRIV(ord2utf)(0x1680, class_uchardata); - *class_uchardata++ = XCL_SINGLE; - class_uchardata += PRIV(ord2utf)(0x180e, class_uchardata); - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x2000, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x200a, class_uchardata); - *class_uchardata++ = XCL_SINGLE; - class_uchardata += PRIV(ord2utf)(0x202f, class_uchardata); - *class_uchardata++ = XCL_SINGLE; - class_uchardata += PRIV(ord2utf)(0x205f, class_uchardata); - *class_uchardata++ = XCL_SINGLE; - class_uchardata += PRIV(ord2utf)(0x3000, class_uchardata); - } -#endif + (void)add_list_to_class(classbits, &class_uchardata, options, cd, + PRIV(hspace_list), NOTACHAR); continue; case ESC_H: - for (c = 0; c < 32; c++) - { - int x = 0xff; - switch (c) - { - case 0x09/8: x ^= 1 << (0x09%8); break; - case 0x20/8: x ^= 1 << (0x20%8); break; - case 0xa0/8: x ^= 1 << (0xa0%8); break; - default: break; - } - classbits[c] |= x; - } -#ifndef COMPILE_PCRE8 - xclass = TRUE; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x0100; - *class_uchardata++ = 0x167f; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x1681; - *class_uchardata++ = 0x180d; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x180f; - *class_uchardata++ = 0x1fff; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x200b; - *class_uchardata++ = 0x202e; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x2030; - *class_uchardata++ = 0x205e; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x2060; - *class_uchardata++ = 0x2fff; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x3001; -#ifdef SUPPORT_UTF - if (utf) - class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata); - else -#endif - *class_uchardata++ = 0xffff; -#elif defined SUPPORT_UTF - if (utf) - { - xclass = TRUE; - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x0100, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x167f, class_uchardata); - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x1681, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x180d, class_uchardata); - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x180f, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x1fff, class_uchardata); - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x200b, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x202e, class_uchardata); - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x2030, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x205e, class_uchardata); - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x2060, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x2fff, class_uchardata); - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x3001, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata); - } -#endif + (void)add_not_list_to_class(classbits, &class_uchardata, options, + cd, PRIV(hspace_list)); continue; case ESC_v: - SETBIT(classbits, 0x0a); /* LF */ - SETBIT(classbits, 0x0b); /* VT */ - SETBIT(classbits, 0x0c); /* FF */ - SETBIT(classbits, 0x0d); /* CR */ - SETBIT(classbits, 0x85); /* NEL */ -#ifndef COMPILE_PCRE8 - xclass = TRUE; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x2028; - *class_uchardata++ = 0x2029; -#elif defined SUPPORT_UTF - if (utf) - { - xclass = TRUE; - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x2028, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x2029, class_uchardata); - } -#endif + (void)add_list_to_class(classbits, &class_uchardata, options, cd, + PRIV(vspace_list), NOTACHAR); continue; case ESC_V: - for (c = 0; c < 32; c++) - { - int x = 0xff; - switch (c) - { - case 0x0a/8: x ^= 1 << (0x0a%8); - x ^= 1 << (0x0b%8); - x ^= 1 << (0x0c%8); - x ^= 1 << (0x0d%8); - break; - case 0x85/8: x ^= 1 << (0x85%8); break; - default: break; - } - classbits[c] |= x; - } - -#ifndef COMPILE_PCRE8 - xclass = TRUE; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x0100; - *class_uchardata++ = 0x2027; - *class_uchardata++ = XCL_RANGE; - *class_uchardata++ = 0x202a; -#ifdef SUPPORT_UTF - if (utf) - class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata); - else -#endif - *class_uchardata++ = 0xffff; -#elif defined SUPPORT_UTF - if (utf) - { - xclass = TRUE; - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x0100, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x2027, class_uchardata); - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(0x202a, class_uchardata); - class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata); - } -#endif + (void)add_not_list_to_class(classbits, &class_uchardata, options, + cd, PRIV(vspace_list)); continue; #ifdef SUPPORT_UCP @@ -4252,11 +5102,10 @@ for (;; ptr++) case ESC_P: { BOOL negated; - int pdata; - int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr); - if (ptype < 0) goto FAILED; - xclass = TRUE; - *class_uchardata++ = ((-c == ESC_p) != negated)? + unsigned int ptype = 0, pdata = 0; + if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr)) + goto FAILED; + *class_uchardata++ = ((escape == ESC_p) != negated)? XCL_PROP : XCL_NOTPROP; *class_uchardata++ = ptype; *class_uchardata++ = pdata; @@ -4275,21 +5124,23 @@ for (;; ptr++) goto FAILED; } class_has_8bitchar--; /* Undo the speculative increase. */ - class_single_char -= 2; /* Undo the speculative increase. */ + class_one_char -= 2; /* Undo the speculative increase. */ c = *ptr; /* Get the final character and fall through */ break; } } - /* Fall through if we have a single character (c >= 0). This may be - greater than 256. */ + /* Fall through if the escape just defined a single character (c >= 0). + This may be greater than 256. */ + + escape = 0; } /* End of backslash handling */ - /* A single character may be followed by '-' to form a range. However, - Perl does not permit ']' to be the end of the range. A '-' character - at the end is treated as a literal. Perl ignores orphaned \E sequences - entirely. The code for handling \Q and \E is messy. */ + /* A character may be followed by '-' to form a range. However, Perl does + not permit ']' to be the end of the range. A '-' character at the end is + treated as a literal. Perl ignores orphaned \E sequences entirely. The + code for handling \Q and \E is messy. */ CHECK_RANGE: while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) @@ -4297,10 +5148,9 @@ for (;; ptr++) inescq = FALSE; ptr += 2; } - oldptr = ptr; - /* Remember \r or \n */ + /* Remember if \r or \n were explicitly used */ if (c == CHAR_CR || c == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF; @@ -4308,7 +5158,7 @@ for (;; ptr++) if (!inescq && ptr[1] == CHAR_MINUS) { - int d; + pcre_uint32 d; ptr += 2; while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2; @@ -4324,12 +5174,17 @@ for (;; ptr++) break; } - if (*ptr == 0 || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET)) + /* Minus (hyphen) at the end of a class is treated as a literal, so put + back the pointer and jump to handle the character that preceded it. */ + + if (*ptr == CHAR_NULL || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET)) { ptr = oldptr; - goto LONE_SINGLE_CHARACTER; + goto CLASS_SINGLE_CHARACTER; } + /* Otherwise, we have a potential range; pick up the next character */ + #ifdef SUPPORT_UTF if (utf) { /* Braces are required because the */ @@ -4339,234 +5194,139 @@ for (;; ptr++) #endif d = *ptr; /* Not UTF-8 mode */ - /* The second part of a range can be a single-character escape, but - not any of the other escapes. Perl 5.6 treats a hyphen as a literal - in such circumstances. */ + /* The second part of a range can be a single-character escape + sequence, but not any of the other escapes. Perl treats a hyphen as a + literal in such circumstances. However, in Perl's warning mode, a + warning is given, so PCRE now faults it as it is almost certainly a + mistake on the user's part. */ - if (!inescq && d == CHAR_BACKSLASH) + if (!inescq) { - d = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE); - if (*errorcodeptr != 0) goto FAILED; - - /* \b is backspace; any other special means the '-' was literal */ - - if (d < 0) + if (d == CHAR_BACKSLASH) { - if (d == -ESC_b) d = CHAR_BS; else + int descape; + descape = check_escape(&ptr, &d, errorcodeptr, cd->bracount, options, TRUE); + if (*errorcodeptr != 0) goto FAILED; + + /* 0 means a character was put into d; \b is backspace; any other + special causes an error. */ + + if (descape != 0) { - ptr = oldptr; - goto LONE_SINGLE_CHARACTER; /* A few lines below */ + if (descape == ESC_b) d = CHAR_BS; else + { + *errorcodeptr = ERR83; + goto FAILED; + } } } + + /* A hyphen followed by a POSIX class is treated in the same way. */ + + else if (d == CHAR_LEFT_SQUARE_BRACKET && + (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || + ptr[1] == CHAR_EQUALS_SIGN) && + check_posix_syntax(ptr, &tempptr)) + { + *errorcodeptr = ERR83; + goto FAILED; + } } /* Check that the two values are in the correct order. Optimize - one-character ranges */ + one-character ranges. */ if (d < c) { *errorcodeptr = ERR8; goto FAILED; } + if (d == c) goto CLASS_SINGLE_CHARACTER; /* A few lines below */ - if (d == c) goto LONE_SINGLE_CHARACTER; /* A few lines below */ + /* We have found a character range, so single character optimizations + cannot be done anymore. Any value greater than 1 indicates that there + is more than one character. */ - /* Remember \r or \n */ + class_one_char = 2; + + /* Remember an explicit \r or \n, and add the range to the class. */ if (d == CHAR_CR || d == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF; - /* Since we found a character range, single character optimizations - cannot be done anymore. */ - class_single_char = 2; - - /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless - matching, we have to use an XCLASS with extra data items. Caseless - matching for characters > 127 is available only if UCP support is - available. */ - -#if defined SUPPORT_UTF && !(defined COMPILE_PCRE8) - if ((d > 255) || (utf && ((options & PCRE_CASELESS) != 0 && d > 127))) -#elif defined SUPPORT_UTF - if (utf && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127))) -#elif !(defined COMPILE_PCRE8) - if (d > 255) -#endif -#if defined SUPPORT_UTF || !(defined COMPILE_PCRE8) - { - xclass = TRUE; - - /* With UCP support, we can find the other case equivalents of - the relevant characters. There may be several ranges. Optimize how - they fit with the basic range. */ - -#ifdef SUPPORT_UCP -#ifndef COMPILE_PCRE8 - if (utf && (options & PCRE_CASELESS) != 0) -#else - if ((options & PCRE_CASELESS) != 0) -#endif - { - unsigned int occ, ocd; - unsigned int cc = c; - unsigned int origd = d; - while (get_othercase_range(&cc, origd, &occ, &ocd)) - { - if (occ >= (unsigned int)c && - ocd <= (unsigned int)d) - continue; /* Skip embedded ranges */ - - if (occ < (unsigned int)c && - ocd >= (unsigned int)c - 1) /* Extend the basic range */ - { /* if there is overlap, */ - c = occ; /* noting that if occ < c */ - continue; /* we can't have ocd > d */ - } /* because a subrange is */ - if (ocd > (unsigned int)d && - occ <= (unsigned int)d + 1) /* always shorter than */ - { /* the basic range. */ - d = ocd; - continue; - } - - if (occ == ocd) - { - *class_uchardata++ = XCL_SINGLE; - } - else - { - *class_uchardata++ = XCL_RANGE; - class_uchardata += PRIV(ord2utf)(occ, class_uchardata); - } - class_uchardata += PRIV(ord2utf)(ocd, class_uchardata); - } - } -#endif /* SUPPORT_UCP */ - - /* Now record the original range, possibly modified for UCP caseless - overlapping ranges. */ - - *class_uchardata++ = XCL_RANGE; -#ifdef SUPPORT_UTF -#ifndef COMPILE_PCRE8 - if (utf) - { - class_uchardata += PRIV(ord2utf)(c, class_uchardata); - class_uchardata += PRIV(ord2utf)(d, class_uchardata); - } - else - { - *class_uchardata++ = c; - *class_uchardata++ = d; - } -#else - class_uchardata += PRIV(ord2utf)(c, class_uchardata); - class_uchardata += PRIV(ord2utf)(d, class_uchardata); -#endif -#else /* SUPPORT_UTF */ - *class_uchardata++ = c; - *class_uchardata++ = d; -#endif /* SUPPORT_UTF */ - - /* With UCP support, we are done. Without UCP support, there is no - caseless matching for UTF characters > 127; we can use the bit map - for the smaller ones. As for 16 bit characters without UTF, we - can still use */ - -#ifdef SUPPORT_UCP -#ifndef COMPILE_PCRE8 - if (utf) -#endif - continue; /* With next character in the class */ -#endif /* SUPPORT_UCP */ - -#if defined SUPPORT_UTF && !defined(SUPPORT_UCP) && !(defined COMPILE_PCRE8) - if (utf) - { - if ((options & PCRE_CASELESS) == 0 || c > 127) continue; - /* Adjust upper limit and fall through to set up the map */ - d = 127; - } - else - { - if (c > 255) continue; - /* Adjust upper limit and fall through to set up the map */ - d = 255; - } -#elif defined SUPPORT_UTF && !defined(SUPPORT_UCP) - if ((options & PCRE_CASELESS) == 0 || c > 127) continue; - /* Adjust upper limit and fall through to set up the map */ - d = 127; -#else - if (c > 255) continue; - /* Adjust upper limit and fall through to set up the map */ - d = 255; -#endif /* SUPPORT_UTF && !SUPPORT_UCP && !COMPILE_PCRE8 */ - } -#endif /* SUPPORT_UTF || !COMPILE_PCRE8 */ - - /* We use the bit map for 8 bit mode, or when the characters fall - partially or entirely to [0-255] ([0-127] for UCP) ranges. */ - - class_has_8bitchar = 1; - - /* We can save a bit of time by skipping this in the pre-compile. */ - - if (lengthptr == NULL) for (; c <= d; c++) - { - classbits[c/8] |= (1 << (c&7)); - if ((options & PCRE_CASELESS) != 0) - { - int uc = cd->fcc[c]; /* flip case */ - classbits[uc/8] |= (1 << (uc&7)); - } - } + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cd, c, d); continue; /* Go get the next char in the class */ } - /* Handle a lone single character - we can get here for a normal - non-escape char, or after \ that introduces a single character or for an - apparent range that isn't. */ + /* Handle a single character - we can get here for a normal non-escape + char, or after \ that introduces a single character or for an apparent + range that isn't. Only the value 1 matters for class_one_char, so don't + increase it if it is already 2 or more ... just in case there's a class + with a zillion characters in it. */ - LONE_SINGLE_CHARACTER: + CLASS_SINGLE_CHARACTER: + if (class_one_char < 2) class_one_char++; - /* Only the value of 1 matters for class_single_char. */ + /* If class_one_char is 1, we have the first single character in the + class, and there have been no prior ranges, or XCLASS items generated by + escapes. If this is the final character in the class, we can optimize by + turning the item into a 1-character OP_CHAR[I] if it's positive, or + OP_NOT[I] if it's negative. In the positive case, it can cause firstchar + to be set. Otherwise, there can be no first char if this item is first, + whatever repeat count may follow. In the case of reqchar, save the + previous value for reinstating. */ - if (class_single_char < 2) class_single_char++; - - /* If class_charcount is 1, we saw precisely one character. As long as - there was no use of \p or \P, in other words, no use of any XCLASS - features, we can optimize. - - The optimization throws away the bit map. We turn the item into a - 1-character OP_CHAR[I] if it's positive, or OP_NOT[I] if it's negative. - In the positive case, it can cause firstchar to be set. Otherwise, there - can be no first char if this item is first, whatever repeat count may - follow. In the case of reqchar, save the previous value for reinstating. */ - - if (class_single_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) + if (class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) { ptr++; zeroreqchar = reqchar; + zeroreqcharflags = reqcharflags; if (negate_class) { - if (firstchar == REQ_UNSET) firstchar = REQ_NONE; +#ifdef SUPPORT_UCP + int d; +#endif + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; zerofirstchar = firstchar; - *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT; -#ifdef SUPPORT_UTF - if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR) - code += PRIV(ord2utf)(c, code); + zerofirstcharflags = firstcharflags; + + /* 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 OP_NOTPROP item instead of OP_NOTI. */ + +#ifdef SUPPORT_UCP + if (utf && (options & PCRE_CASELESS) != 0 && + (d = UCD_CASESET(c)) != 0) + { + *code++ = OP_NOTPROP; + *code++ = PT_CLIST; + *code++ = d; + } else #endif - *code++ = c; - goto NOT_CHAR; + /* Char has only one other case, or UCP not available */ + + { + *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT; +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 + if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR) + code += PRIV(ord2utf)(c, code); + else +#endif + *code++ = c; + } + + /* We are finished with this character class */ + + goto END_CLASS; } /* For a single, positive character, get the value into mcbuffer, and then we can handle this with the normal one-character code. */ -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR) mclength = PRIV(ord2utf)(c, mcbuffer); else @@ -4578,89 +5338,51 @@ for (;; ptr++) goto ONE_CHAR; } /* End of 1-char optimization */ - /* Handle a character that cannot go in the bit map. */ + /* There is more than one character in the class, or an XCLASS item + has been generated. Add this character to the class. */ -#if defined SUPPORT_UTF && !(defined COMPILE_PCRE8) - if ((c > 255) || (utf && ((options & PCRE_CASELESS) != 0 && c > 127))) -#elif defined SUPPORT_UTF - if (utf && (c > 255 || ((options & PCRE_CASELESS) != 0 && c > 127))) -#elif !(defined COMPILE_PCRE8) - if (c > 255) -#endif - -#if defined SUPPORT_UTF || !(defined COMPILE_PCRE8) - { - xclass = TRUE; - *class_uchardata++ = XCL_SINGLE; -#ifdef SUPPORT_UTF -#ifndef COMPILE_PCRE8 - /* In non 8 bit mode, we can get here even if we are not in UTF mode. */ - if (!utf) - *class_uchardata++ = c; - else -#endif - class_uchardata += PRIV(ord2utf)(c, class_uchardata); -#else /* SUPPORT_UTF */ - *class_uchardata++ = c; -#endif /* SUPPORT_UTF */ - -#ifdef SUPPORT_UCP -#ifdef COMPILE_PCRE8 - if ((options & PCRE_CASELESS) != 0) -#else - /* In non 8 bit mode, we can get here even if we are not in UTF mode. */ - if (utf && (options & PCRE_CASELESS) != 0) -#endif - { - unsigned int othercase; - if ((int)(othercase = UCD_OTHERCASE(c)) != c) - { - *class_uchardata++ = XCL_SINGLE; - class_uchardata += PRIV(ord2utf)(othercase, class_uchardata); - } - } -#endif /* SUPPORT_UCP */ - - } - else -#endif /* SUPPORT_UTF || COMPILE_PCRE16 */ - - /* Handle a single-byte character */ - { - class_has_8bitchar = 1; - classbits[c/8] |= (1 << (c&7)); - if ((options & PCRE_CASELESS) != 0) - { - c = cd->fcc[c]; /* flip case */ - classbits[c/8] |= (1 << (c&7)); - } - } + class_has_8bitchar += + add_to_class(classbits, &class_uchardata, options, cd, c, c); } /* Loop until ']' reached. This "while" is the end of the "do" far above. If we are at the end of an internal nested string, revert to the outer string. */ - while (((c = *(++ptr)) != 0 || + while (((c = *(++ptr)) != CHAR_NULL || (nestptr != NULL && - (ptr = nestptr, nestptr = NULL, c = *(++ptr)) != 0)) && + (ptr = nestptr, nestptr = NULL, c = *(++ptr)) != CHAR_NULL)) && (c != CHAR_RIGHT_SQUARE_BRACKET || inescq)); /* Check for missing terminating ']' */ - if (c == 0) + if (c == CHAR_NULL) { *errorcodeptr = ERR6; goto FAILED; } + /* We will need an XCLASS if data has been placed in class_uchardata. In + the second phase this is a sufficient test. However, in the pre-compile + phase, class_uchardata gets emptied to prevent workspace overflow, so it + only if the very last character in the class needs XCLASS will it contain + anything at this point. For this reason, xclass gets set TRUE above when + uchar_classdata is emptied, and that's why this code is the way it is here + instead of just doing a test on class_uchardata below. */ + +#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + if (class_uchardata > class_uchardata_base) xclass = TRUE; +#endif + /* If this is the first thing in the branch, there can be no first char setting, whatever the repeat count. Any reqchar setting must remain unchanged after any kind of repeat. */ - if (firstchar == REQ_UNSET) firstchar = REQ_NONE; + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; zerofirstchar = firstchar; + zerofirstcharflags = firstcharflags; zeroreqchar = reqchar; + zeroreqcharflags = reqcharflags; /* If there are characters with values > 255, we have to compile an extended class, with its own opcode, unless there was a negated special @@ -4716,7 +5438,8 @@ for (;; ptr++) memcpy(code, classbits, 32); } code += 32 / sizeof(pcre_uchar); - NOT_CHAR: + + END_CLASS: break; @@ -4754,7 +5477,9 @@ for (;; ptr++) if (repeat_min == 0) { firstchar = zerofirstchar; /* Adjust for zero repeat */ + firstcharflags = zerofirstcharflags; reqchar = zeroreqchar; /* Ditto */ + reqcharflags = zeroreqcharflags; } /* Remember whether this is a variable length repeat */ @@ -4769,6 +5494,34 @@ for (;; ptr++) tempcode = previous; + /* Before checking for a possessive quantifier, we must skip over + whitespace and comments in extended mode because Perl allows white space at + this point. */ + + if ((options & PCRE_EXTENDED) != 0) + { + const pcre_uchar *p = ptr + 1; + for (;;) + { + while (MAX_255(*p) && (cd->ctypes[*p] & ctype_space) != 0) p++; + if (*p != CHAR_NUMBER_SIGN) break; + p++; + while (*p != CHAR_NULL) + { + if (IS_NEWLINE(p)) /* For non-fixed-length newline cases, */ + { /* IS_NEWLINE sets cd->nllen. */ + p += cd->nllen; + break; + } + p++; +#ifdef SUPPORT_UTF + if (utf) FORWARDCHAR(p); +#endif + } /* Loop for comment characters */ + } /* Loop for multiple comments */ + ptr = p - 1; /* Character before the next significant one. */ + } + /* If the next character is '+', we have a possessive quantifier. This implies greediness, whatever the setting of the PCRE_UNGREEDY option. If the next character is '?' this is a minimizing repeat, by default, @@ -4840,7 +5593,7 @@ for (;; ptr++) hold the length of the character in bytes, plus UTF_LENGTH to flag that it's a length rather than a small character. */ -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && NOT_FIRSTCHAR(code[-1])) { pcre_uchar *lastchar = code - 1; @@ -4857,20 +5610,10 @@ for (;; ptr++) { c = code[-1]; if (*previous <= OP_CHARI && repeat_min > 1) - reqchar = c | req_caseopt | cd->req_varyopt; - } - - /* If the repetition is unlimited, it pays to see if the next thing on - the line is something that cannot possibly match this character. If so, - automatically possessifying this item gains some performance in the case - where the match fails. */ - - if (!possessive_quantifier && - repeat_max < 0 && - check_auto_possessive(previous, utf, ptr + 1, options, cd)) - { - repeat_type = 0; /* Force greedy */ - possessive_quantifier = TRUE; + { + reqchar = c; + reqcharflags = req_caseopt | cd->req_varyopt; + } } goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ @@ -4890,14 +5633,6 @@ for (;; ptr++) op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ c = *previous; - if (!possessive_quantifier && - repeat_max < 0 && - check_auto_possessive(previous, utf, ptr + 1, options, cd)) - { - repeat_type = 0; /* Force greedy */ - possessive_quantifier = TRUE; - } - OUTPUT_SINGLE_REPEAT: if (*previous == OP_PROP || *previous == OP_NOTPROP) { @@ -4914,16 +5649,6 @@ for (;; ptr++) if (repeat_max == 0) goto END_REPEAT; - /*--------------------------------------------------------------------*/ - /* This code is obsolete from release 8.00; the restriction was finally - removed: */ - - /* All real repeats make it impossible to handle partial matching (maybe - one day we will be able to remove this restriction). */ - - /* if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; */ - /*--------------------------------------------------------------------*/ - /* Combine the op_type with the repeat_type */ repeat_type += op_type; @@ -4976,7 +5701,7 @@ for (;; ptr++) if (repeat_max < 0) { -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && (c & UTF_LENGTH) != 0) { memcpy(code, utf_chars, IN_UCHARS(c & 7)); @@ -5001,7 +5726,7 @@ for (;; ptr++) else if (repeat_max != repeat_min) { -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && (c & UTF_LENGTH) != 0) { memcpy(code, utf_chars, IN_UCHARS(c & 7)); @@ -5031,7 +5756,7 @@ for (;; ptr++) /* The character or character type itself comes last in all cases. */ -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && (c & UTF_LENGTH) != 0) { memcpy(code, utf_chars, IN_UCHARS(c & 7)); @@ -5056,13 +5781,12 @@ for (;; ptr++) /* If previous was a character class or a back reference, we put the repeat stuff after it, but just skip the item if the repeat was {0,0}. */ - else if (*previous == OP_CLASS || - *previous == OP_NCLASS || + else if (*previous == OP_CLASS || *previous == OP_NCLASS || #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 *previous == OP_XCLASS || #endif - *previous == OP_REF || - *previous == OP_REFI) + *previous == OP_REF || *previous == OP_REFI || + *previous == OP_DNREF || *previous == OP_DNREFI) { if (repeat_max == 0) { @@ -5070,16 +5794,6 @@ for (;; ptr++) goto END_REPEAT; } - /*--------------------------------------------------------------------*/ - /* This code is obsolete from release 8.00; the restriction was finally - removed: */ - - /* All real repeats make it impossible to handle partial matching (maybe - one day we will be able to remove this restriction). */ - - /* if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; */ - /*--------------------------------------------------------------------*/ - if (repeat_min == 0 && repeat_max == -1) *code++ = OP_CRSTAR + repeat_type; else if (repeat_min == 1 && repeat_max == -1) @@ -5100,8 +5814,9 @@ for (;; ptr++) opcodes such as BRA and CBRA, as this is the place where they get converted into the more special varieties such as BRAPOS and SBRA. A test for >= OP_ASSERT and <= OP_COND includes ASSERT, ASSERT_NOT, ASSERTBACK, - ASSERTBACK_NOT, ONCE, BRA, CBRA, and COND. Originally, PCRE did not allow - repetition of assertions, but now it does, for Perl compatibility. */ + ASSERTBACK_NOT, ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND. + Originally, PCRE did not allow repetition of assertions, but now it does, + for Perl compatibility. */ else if (*previous >= OP_ASSERT && *previous <= OP_COND) { @@ -5119,7 +5834,7 @@ for (;; ptr++) /* There is no sense in actually repeating assertions. The only potential use of repetition is in cases when the assertion is optional. Therefore, if the minimum is greater than zero, just ignore the repeat. If the - maximum is not not zero or one, set it to 1. */ + maximum is not zero or one, set it to 1. */ if (*previous < OP_ONCE) /* Assertion */ { @@ -5239,7 +5954,11 @@ for (;; ptr++) else { - if (groupsetfirstchar && reqchar < 0) reqchar = firstchar; + if (groupsetfirstchar && reqcharflags < 0) + { + reqchar = firstchar; + reqcharflags = firstcharflags; + } for (i = 1; i < repeat_min; i++) { @@ -5418,7 +6137,7 @@ for (;; ptr++) pcre_uchar *scode = bracode; do { - if (could_be_empty_branch(scode, ketcode, utf, cd)) + if (could_be_empty_branch(scode, ketcode, utf, cd, NULL)) { *bracode += OP_SBRA - OP_BRA; break; @@ -5488,43 +6207,105 @@ for (;; ptr++) goto FAILED; } - /* If the character following a repeat is '+', or if certain optimization - tests above succeeded, possessive_quantifier is TRUE. For some opcodes, - there are special alternative opcodes for this case. For anything else, we - wrap the entire repeated item inside OP_ONCE brackets. Logically, the '+' - notation is just syntactic sugar, taken from Sun's Java package, but the - special opcodes can optimize it. + /* If the character following a repeat is '+', possessive_quantifier is + TRUE. For some opcodes, there are special alternative opcodes for this + case. For anything else, we wrap the entire repeated item inside OP_ONCE + brackets. Logically, the '+' notation is just syntactic sugar, taken from + Sun's Java package, but the special opcodes can optimize it. Some (but not all) possessively repeated subpatterns have already been completely handled in the code just above. For them, possessive_quantifier - is always FALSE at this stage. - - Note that the repeated item starts at tempcode, not at previous, which - might be the first part of a string whose (former) last char we repeated. - - Possessifying an 'exact' quantifier has no effect, so we can ignore it. But - an 'upto' may follow. We skip over an 'exact' item, and then test the - length of what remains before proceeding. */ + is always FALSE at this stage. Note that the repeated item starts at + tempcode, not at previous, which might be the first part of a string whose + (former) last char we repeated. */ if (possessive_quantifier) { int len; - if (*tempcode == OP_TYPEEXACT) + /* Possessifying an EXACT quantifier has no effect, so we can ignore it. + However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6}, + {5,}, or {5,10}). We skip over an EXACT item; if the length of what + remains is greater than zero, there's a further opcode that can be + handled. If not, do nothing, leaving the EXACT alone. */ + + switch(*tempcode) + { + case OP_TYPEEXACT: tempcode += PRIV(OP_lengths)[*tempcode] + ((tempcode[1 + IMM2_SIZE] == OP_PROP || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0); + break; - else if (*tempcode == OP_EXACT || *tempcode == OP_NOTEXACT) - { + /* CHAR opcodes are used for exacts whose count is 1. */ + + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + case OP_EXACT: + case OP_EXACTI: + case OP_NOTEXACT: + case OP_NOTEXACTI: tempcode += PRIV(OP_lengths)[*tempcode]; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(tempcode[-1])) tempcode += GET_EXTRALEN(tempcode[-1]); +#endif + break; + + /* For the class opcodes, the repeat operator appears at the end; + adjust tempcode to point to it. */ + + case OP_CLASS: + case OP_NCLASS: + tempcode += 1 + 32/sizeof(pcre_uchar); + break; + +#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + case OP_XCLASS: + tempcode += GET(tempcode, 1); + break; #endif } + /* If tempcode is equal to code (which points to the end of the repeated + item), it means we have skipped an EXACT item but there is no following + QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In + all other cases, tempcode will be pointing to the repeat opcode, and will + be less than code, so the value of len will be greater than 0. */ + len = (int)(code - tempcode); + if (len > 0) + { + unsigned int repcode = *tempcode; + + /* There is a table for possessifying opcodes, all of which are less + than OP_CALLOUT. A zero entry means there is no possessified version. + */ + + if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0) + *tempcode = opcode_possessify[repcode]; + + /* For opcode without a special possessified version, wrap the item in + ONCE brackets. Because we are moving code along, we must ensure that any + pending recursive references are updated. */ + + else + { + *code = OP_END; + adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm); + memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len)); + code += 1 + LINK_SIZE; + len += 1 + LINK_SIZE; + tempcode[0] = OP_ONCE; + *code++ = OP_KET; + PUTINC(code, 0, len); + PUT(tempcode, 1, len); + } + } + +#ifdef NEVER if (len > 0) switch (*tempcode) { case OP_STAR: *tempcode = OP_POSSTAR; break; @@ -5552,6 +6333,11 @@ for (;; ptr++) case OP_TYPEQUERY: *tempcode = OP_TYPEPOSQUERY; break; case OP_TYPEUPTO: *tempcode = OP_TYPEPOSUPTO; break; + case OP_CRSTAR: *tempcode = OP_CRPOSSTAR; break; + case OP_CRPLUS: *tempcode = OP_CRPOSPLUS; break; + case OP_CRQUERY: *tempcode = OP_CRPOSQUERY; break; + case OP_CRRANGE: *tempcode = OP_CRPOSRANGE; break; + /* Because we are moving code along, we must ensure that any pending recursive references are updated. */ @@ -5567,6 +6353,7 @@ for (;; ptr++) PUT(tempcode, 1, len); break; } +#endif } /* In all case we no longer have a previous item. We also set the @@ -5614,9 +6401,9 @@ for (;; ptr++) if (*ptr == CHAR_COLON) { arg = ++ptr; - while (*ptr != 0 && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; + while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; arglen = (int)(ptr - arg); - if (arglen > (int)MAX_MARK) + if ((unsigned int)arglen > MAX_MARK) { *errorcodeptr = ERR75; goto FAILED; @@ -5636,6 +6423,8 @@ for (;; ptr++) if (namelen == verbs[i].len && STRNCMP_UC_C8(name, vn, namelen) == 0) { + int setverb; + /* Check for open captures before ACCEPT and convert it to ASSERT_ACCEPT if in an assertion. */ @@ -5653,10 +6442,11 @@ for (;; ptr++) *code++ = OP_CLOSE; PUT2INC(code, 0, oc->number); } - *code++ = (cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT; + setverb = *code++ = + (cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT; /* Do not set firstchar after *ACCEPT */ - if (firstchar == REQ_UNSET) firstchar = REQ_NONE; + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; } /* Handle other cases with/without an argument */ @@ -5668,8 +6458,7 @@ for (;; ptr++) *errorcodeptr = ERR66; goto FAILED; } - *code = verbs[i].op; - if (*code++ == OP_THEN) cd->external_flags |= PCRE_HASTHEN; + setverb = *code++ = verbs[i].op; } else @@ -5679,14 +6468,28 @@ for (;; ptr++) *errorcodeptr = ERR59; goto FAILED; } - *code = verbs[i].op_arg; - if (*code++ == OP_THEN_ARG) cd->external_flags |= PCRE_HASTHEN; + setverb = *code++ = verbs[i].op_arg; *code++ = arglen; memcpy(code, arg, IN_UCHARS(arglen)); code += arglen; *code++ = 0; } + switch (setverb) + { + case OP_THEN: + case OP_THEN_ARG: + cd->external_flags |= PCRE_HASTHEN; + break; + + case OP_PRUNE: + case OP_PRUNE_ARG: + case OP_SKIP: + case OP_SKIP_ARG: + cd->had_pruneorskip = TRUE; + break; + } + break; /* Found verb, exit loop */ } @@ -5712,8 +6515,8 @@ for (;; ptr++) { case CHAR_NUMBER_SIGN: /* Comment; skip to ket */ ptr++; - while (*ptr != 0 && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; - if (*ptr == 0) + while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; + if (*ptr == CHAR_NULL) { *errorcodeptr = ERR18; goto FAILED; @@ -5736,30 +6539,44 @@ for (;; ptr++) /* ------------------------------------------------------------ */ case CHAR_LEFT_PARENTHESIS: bravalue = OP_COND; /* Conditional group */ + tempptr = ptr; /* A condition can be an assertion, a number (referring to a numbered - group), a name (referring to a named group), or 'R', referring to - recursion. R and R&name are also permitted for recursion tests. + group's having been set), a name (referring to a named group), or 'R', + referring to recursion. R and R&name are also permitted for + recursion tests. - There are several syntaxes for testing a named group: (?(name)) is used - by Python; Perl 5.10 onwards uses (?() or (?('name')). + There are ways of testing a named group: (?(name)) is used by Python; + Perl 5.10 onwards uses (?() or (?('name')). - There are two unfortunate ambiguities, caused by history. (a) 'R' can - be the recursive thing or the name 'R' (and similarly for 'R' followed - by digits), and (b) a number could be a name that consists of digits. - In both cases, we look for a name first; if not found, we try the other - cases. */ + There is one unfortunate ambiguity, caused by history. 'R' can be the + recursive thing or the name 'R' (and similarly for 'R' followed by + digits). We look for a name first; if not found, we try the other case. + + For compatibility with auto-callouts, we allow a callout to be + specified before a condition that is an assertion. First, check for the + syntax of a callout; if found, adjust the temporary pointer that is + used to check for an assertion condition. That's all that is needed! */ + + if (ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_C) + { + for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break; + if (ptr[i] == CHAR_RIGHT_PARENTHESIS) + tempptr += i + 1; + } /* For conditions that are assertions, check the syntax, and then exit the switch. This will take control down to where bracketed groups, including assertions, are processed. */ - if (ptr[1] == CHAR_QUESTION_MARK && (ptr[2] == CHAR_EQUALS_SIGN || - ptr[2] == CHAR_EXCLAMATION_MARK || ptr[2] == CHAR_LESS_THAN_SIGN)) + if (tempptr[1] == CHAR_QUESTION_MARK && + (tempptr[2] == CHAR_EQUALS_SIGN || + tempptr[2] == CHAR_EXCLAMATION_MARK || + tempptr[2] == CHAR_LESS_THAN_SIGN)) break; - /* Most other conditions use OP_CREF (a couple change to OP_RREF - below), and all need to skip 1+IMM2_SIZE bytes at the start of the group. */ + /* Other conditions use OP_CREF/OP_DNCREF/OP_RREF/OP_DNRREF, and all + need to skip at least 1+IMM2_SIZE bytes at the start of the group. */ code[1+LINK_SIZE] = OP_CREF; skipbytes = 1+IMM2_SIZE; @@ -5767,7 +6584,8 @@ for (;; ptr++) /* Check for a test for recursion in a named group. */ - if (ptr[1] == CHAR_R && ptr[2] == CHAR_AMPERSAND) + ptr++; + if (*ptr == CHAR_R && ptr[1] == CHAR_AMPERSAND) { terminator = -1; ptr += 2; @@ -5775,50 +6593,71 @@ for (;; ptr++) } /* Check for a test for a named group's having been set, using the Perl - syntax (?() or (?('name') */ + syntax (?() or (?('name'), and also allow for the original PCRE + syntax of (?(name) or for (?(+n), (?(-n), and just (?(n). */ - else if (ptr[1] == CHAR_LESS_THAN_SIGN) + else if (*ptr == CHAR_LESS_THAN_SIGN) { terminator = CHAR_GREATER_THAN_SIGN; ptr++; } - else if (ptr[1] == CHAR_APOSTROPHE) + else if (*ptr == CHAR_APOSTROPHE) { terminator = CHAR_APOSTROPHE; ptr++; } else { - terminator = 0; - if (ptr[1] == CHAR_MINUS || ptr[1] == CHAR_PLUS) refsign = *(++ptr); + terminator = CHAR_NULL; + if (*ptr == CHAR_MINUS || *ptr == CHAR_PLUS) refsign = *ptr++; + else if (IS_DIGIT(*ptr)) refsign = 0; } - /* We now expect to read a name; any thing else is an error */ + /* Handle a number */ - if (!MAX_255(ptr[1]) || (cd->ctypes[ptr[1]] & ctype_word) == 0) + if (refsign >= 0) { - ptr += 1; /* To get the right offset */ - *errorcodeptr = ERR28; - goto FAILED; + recno = 0; + while (IS_DIGIT(*ptr)) + { + recno = recno * 10 + (int)(*ptr - CHAR_0); + ptr++; + } } - /* Read the name, but also get it as a number if it's all digits */ + /* Otherwise we expect to read a name; anything else is an error. When + a name is one of a number of duplicates, a different opcode is used and + it needs more memory. Unfortunately we cannot tell whether a name is a + duplicate in the first pass, so we have to allow for more memory. */ - recno = 0; - name = ++ptr; - while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) + else { - if (recno >= 0) - recno = (IS_DIGIT(*ptr))? recno * 10 + *ptr - CHAR_0 : -1; - ptr++; + if (IS_DIGIT(*ptr)) + { + *errorcodeptr = ERR84; + goto FAILED; + } + if (!MAX_255(*ptr) || (cd->ctypes[*ptr] & ctype_word) == 0) + { + *errorcodeptr = ERR28; /* Assertion expected */ + goto FAILED; + } + name = ptr++; + while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) + { + ptr++; + } + namelen = (int)(ptr - name); + if (lengthptr != NULL) *lengthptr += IMM2_SIZE; } - namelen = (int)(ptr - name); - if ((terminator > 0 && *ptr++ != terminator) || + /* Check the terminator */ + + if ((terminator > 0 && *ptr++ != (pcre_uchar)terminator) || *ptr++ != CHAR_RIGHT_PARENTHESIS) { - ptr--; /* Error offset */ - *errorcodeptr = ERR26; + ptr--; /* Error offset */ + *errorcodeptr = ERR26; /* Malformed number or name */ goto FAILED; } @@ -5827,18 +6666,18 @@ for (;; ptr++) if (lengthptr != NULL) break; /* In the real compile we do the work of looking for the actual - reference. If the string started with "+" or "-" we require the rest to - be digits, in which case recno will be set. */ + reference. If refsign is not negative, it means we have a number in + recno. */ - if (refsign > 0) + if (refsign >= 0) { if (recno <= 0) { - *errorcodeptr = ERR58; + *errorcodeptr = ERR35; goto FAILED; } - recno = (refsign == CHAR_MINUS)? - cd->bracount - recno + 1 : recno +cd->bracount; + if (refsign != 0) recno = (refsign == CHAR_MINUS)? + cd->bracount - recno + 1 : recno + cd->bracount; if (recno <= 0 || recno > cd->final_bracount) { *errorcodeptr = ERR15; @@ -5848,11 +6687,7 @@ for (;; ptr++) break; } - /* Otherwise (did not start with "+" or "-"), start by looking for the - name. If we find a name, add one to the opcode to change OP_CREF or - OP_RREF into OP_NCREF or OP_NRREF. These behave exactly the same, - except they record that the reference was originally to a name. The - information is used to check duplicate names. */ + /* Otherwise look for the name. */ slot = cd->name_table; for (i = 0; i < cd->names_found; i++) @@ -5861,31 +6696,42 @@ for (;; ptr++) slot += cd->name_entry_size; } - /* Found a previous named subpattern */ + /* Found the named subpattern. If the name is duplicated, add one to + the opcode to change CREF/RREF into DNCREF/DNRREF and insert + appropriate data values. Otherwise, just insert the unique subpattern + number. */ if (i < cd->names_found) { - recno = GET2(slot, 0); - PUT2(code, 2+LINK_SIZE, recno); - code[1+LINK_SIZE]++; + int offset = i++; + int count = 1; + recno = GET2(slot, 0); /* Number from first found */ + for (; i < cd->names_found; i++) + { + slot += cd->name_entry_size; + if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) != 0) break; + count++; + } + if (count > 1) + { + PUT2(code, 2+LINK_SIZE, offset); + PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count); + skipbytes += IMM2_SIZE; + code[1+LINK_SIZE]++; + } + else /* Not a duplicated name */ + { + PUT2(code, 2+LINK_SIZE, recno); + } } - /* Search the pattern for a forward reference */ + /* If terminator == CHAR_NULL it means that the name followed directly + after the opening parenthesis [e.g. (?(abc)...] and in this case there + are some further alternatives to try. For the cases where terminator != + CHAR_NULL [things like (?(... or (?('name')... or (?(R&name)... ] + we have now checked all the possibilities, so give an error. */ - else if ((i = find_parens(cd, name, namelen, - (options & PCRE_EXTENDED) != 0, utf)) > 0) - { - PUT2(code, 2+LINK_SIZE, i); - code[1+LINK_SIZE]++; - } - - /* If terminator == 0 it means that the name followed directly after - the opening parenthesis [e.g. (?(abc)...] and in this case there are - some further alternatives to try. For the cases where terminator != 0 - [things like (?(... or (?('name')... or (?(R&name)... ] we have - now checked all the possibilities, so give an error. */ - - else if (terminator != 0) + else if (terminator != CHAR_NULL) { *errorcodeptr = ERR15; goto FAILED; @@ -5920,19 +6766,11 @@ for (;; ptr++) skipbytes = 1; } - /* Check for the "name" actually being a subpattern number. We are - in the second pass here, so final_bracount is set. */ - - else if (recno > 0 && recno <= cd->final_bracount) - { - PUT2(code, 2+LINK_SIZE, recno); - } - - /* Either an unidentified subpattern, or a reference to (?(0) */ + /* Reference to an unidentified subpattern. */ else { - *errorcodeptr = (recno == 0)? ERR35: ERR15; + *errorcodeptr = ERR15; goto FAILED; } break; @@ -5945,11 +6783,18 @@ for (;; ptr++) ptr++; break; + /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird + thing to do, but Perl allows all assertions to be quantified, and when + they contain capturing parentheses there may be a potential use for + this feature. Not that that applies to a quantified (?!) but we allow + it for uniformity. */ /* ------------------------------------------------------------ */ case CHAR_EXCLAMATION_MARK: /* Negative lookahead */ ptr++; - if (*ptr == CHAR_RIGHT_PARENTHESIS) /* Optimize (?!) */ + if (*ptr == CHAR_RIGHT_PARENTHESIS && ptr[1] != CHAR_ASTERISK && + ptr[1] != CHAR_PLUS && ptr[1] != CHAR_QUESTION_MARK && + (ptr[1] != CHAR_LEFT_CURLY_BRACKET || !is_counted_repeat(ptr+2))) { *code++ = OP_FAIL; previous = NULL; @@ -6042,124 +6887,110 @@ for (;; ptr++) /* ------------------------------------------------------------ */ DEFINE_NAME: /* Come here from (?< handling */ case CHAR_APOSTROPHE: + terminator = (*ptr == CHAR_LESS_THAN_SIGN)? + CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; + name = ++ptr; + if (IS_DIGIT(*ptr)) { - terminator = (*ptr == CHAR_LESS_THAN_SIGN)? - CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; - name = ++ptr; + *errorcodeptr = ERR84; /* Group name must start with non-digit */ + goto FAILED; + } + while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++; + namelen = (int)(ptr - name); - while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++; - namelen = (int)(ptr - name); + /* In the pre-compile phase, do a syntax check, remember the longest + name, and then remember the group in a vector, expanding it if + necessary. Duplicates for the same number are skipped; other duplicates + are checked for validity. In the actual compile, there is nothing to + do. */ - /* In the pre-compile phase, just do a syntax check. */ + if (lengthptr != NULL) + { + named_group *ng; + pcre_uint32 number = cd->bracount + 1; - if (lengthptr != NULL) + if (*ptr != (pcre_uchar)terminator) { - if (*ptr != terminator) + *errorcodeptr = ERR42; + goto FAILED; + } + + if (cd->names_found >= MAX_NAME_COUNT) + { + *errorcodeptr = ERR49; + goto FAILED; + } + + if (namelen + IMM2_SIZE + 1 > cd->name_entry_size) + { + cd->name_entry_size = namelen + IMM2_SIZE + 1; + if (namelen > MAX_NAME_SIZE) { - *errorcodeptr = ERR42; + *errorcodeptr = ERR48; goto FAILED; } - if (cd->names_found >= MAX_NAME_COUNT) - { - *errorcodeptr = ERR49; - goto FAILED; - } - if (namelen + IMM2_SIZE + 1 > cd->name_entry_size) - { - cd->name_entry_size = namelen + IMM2_SIZE + 1; - if (namelen > MAX_NAME_SIZE) - { - *errorcodeptr = ERR48; - goto FAILED; - } - } } - /* In the real compile, create the entry in the table, maintaining - alphabetical order. Duplicate names for different numbers are - permitted only if PCRE_DUPNAMES is set. Duplicate names for the same - number are always OK. (An existing number can be re-used if (?| - appears in the pattern.) In either event, a duplicate name results in - a duplicate entry in the table, even if the number is the same. This - is because the number of names, and hence the table size, is computed - in the pre-compile, and it affects various numbers and pointers which - would all have to be modified, and the compiled code moved down, if - duplicates with the same number were omitted from the table. This - doesn't seem worth the hassle. However, *different* names for the - same number are not permitted. */ + /* Scan the list to check for duplicates. For duplicate names, if the + number is the same, break the loop, which causes the name to be + discarded; otherwise, if DUPNAMES is not set, give an error. + If it is set, allow the name with a different number, but continue + scanning in case this is a duplicate with the same number. For + non-duplicate names, give an error if the number is duplicated. */ - else + ng = cd->named_groups; + for (i = 0; i < cd->names_found; i++, ng++) { - BOOL dupname = FALSE; - slot = cd->name_table; - - for (i = 0; i < cd->names_found; i++) + if (namelen == ng->length && + STRNCMP_UC_UC(name, ng->name, namelen) == 0) { - int crc = memcmp(name, slot+IMM2_SIZE, IN_UCHARS(namelen)); - if (crc == 0) + if (ng->number == number) break; + if ((options & PCRE_DUPNAMES) == 0) { - if (slot[IMM2_SIZE+namelen] == 0) - { - if (GET2(slot, 0) != cd->bracount + 1 && - (options & PCRE_DUPNAMES) == 0) - { - *errorcodeptr = ERR43; - goto FAILED; - } - else dupname = TRUE; - } - else crc = -1; /* Current name is a substring */ + *errorcodeptr = ERR43; + goto FAILED; + } + cd->dupnames = TRUE; /* Duplicate names exist */ + } + else if (ng->number == number) + { + *errorcodeptr = ERR65; + goto FAILED; + } + } + + if (i >= cd->names_found) /* Not a duplicate with same number */ + { + /* Increase the list size if necessary */ + + if (cd->names_found >= cd->named_group_list_size) + { + int newsize = cd->named_group_list_size * 2; + named_group *newspace = (PUBL(malloc)) + (newsize * sizeof(named_group)); + + if (newspace == NULL) + { + *errorcodeptr = ERR21; + goto FAILED; } - /* Make space in the table and break the loop for an earlier - name. For a duplicate or later name, carry on. We do this for - duplicates so that in the simple case (when ?(| is not used) they - are in order of their numbers. */ - - if (crc < 0) - { - memmove(slot + cd->name_entry_size, slot, - IN_UCHARS((cd->names_found - i) * cd->name_entry_size)); - break; - } - - /* Continue the loop for a later or duplicate name */ - - slot += cd->name_entry_size; + memcpy(newspace, cd->named_groups, + cd->named_group_list_size * sizeof(named_group)); + if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE) + (PUBL(free))((void *)cd->named_groups); + cd->named_groups = newspace; + cd->named_group_list_size = newsize; } - /* For non-duplicate names, check for a duplicate number before - adding the new name. */ - - if (!dupname) - { - pcre_uchar *cslot = cd->name_table; - for (i = 0; i < cd->names_found; i++) - { - if (cslot != slot) - { - if (GET2(cslot, 0) == cd->bracount + 1) - { - *errorcodeptr = ERR65; - goto FAILED; - } - } - else i--; - cslot += cd->name_entry_size; - } - } - - PUT2(slot, 0, cd->bracount + 1); - memcpy(slot + IMM2_SIZE, name, IN_UCHARS(namelen)); - slot[IMM2_SIZE + namelen] = 0; + cd->named_groups[cd->names_found].name = name; + cd->named_groups[cd->names_found].length = namelen; + cd->named_groups[cd->names_found].number = number; + cd->names_found++; } } - /* In both pre-compile and compile, count the number of names we've - encountered. */ - - cd->names_found++; - ptr++; /* Move past > or ' */ + ptr++; /* Move past > or ' in both passes. */ goto NUMBERED_GROUP; @@ -6177,6 +7008,11 @@ for (;; ptr++) NAMED_REF_OR_RECURSE: name = ++ptr; + if (IS_DIGIT(*ptr)) + { + *errorcodeptr = ERR84; /* Group name must start with non-digit */ + goto FAILED; + } while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++; namelen = (int)(ptr - name); @@ -6189,14 +7025,14 @@ for (;; ptr++) if (lengthptr != NULL) { - const pcre_uchar *temp; + named_group *ng; if (namelen == 0) { *errorcodeptr = ERR62; goto FAILED; } - if (*ptr != terminator) + if (*ptr != (pcre_uchar)terminator) { *errorcodeptr = ERR42; goto FAILED; @@ -6207,27 +7043,29 @@ for (;; ptr++) goto FAILED; } - /* The name table does not exist in the first pass, so we cannot - do a simple search as in the code below. Instead, we have to scan the - pattern to find the number. It is important that we scan it only as - far as we have got because the syntax of named subpatterns has not - been checked for the rest of the pattern, and find_parens() assumes - correct syntax. In any case, it's a waste of resources to scan - further. We stop the scan at the current point by temporarily - adjusting the value of cd->endpattern. */ + /* 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. */ - temp = cd->end_pattern; - cd->end_pattern = ptr; - recno = find_parens(cd, name, namelen, - (options & PCRE_EXTENDED) != 0, utf); - cd->end_pattern = temp; - if (recno < 0) recno = 0; /* Forward ref; set dummy number */ + 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++; } - /* In the real compile, seek the name in the table. We check the name + /* In the real compile, search the name table. We check the name first, and then check that we have reached the end of the name in the - table. That way, if the name that is longer than any in the table, - the comparison will fail without reading beyond the table entry. */ + table. That way, if the name is longer than any in the table, the + comparison will fail without reading beyond the table entry. */ else { @@ -6240,24 +7078,76 @@ for (;; ptr++) slot += cd->name_entry_size; } - if (i < cd->names_found) /* Back reference */ + if (i < cd->names_found) { recno = GET2(slot, 0); } - else if ((recno = /* Forward back reference */ - find_parens(cd, name, namelen, - (options & PCRE_EXTENDED) != 0, utf)) <= 0) + else { *errorcodeptr = ERR15; goto FAILED; } } - /* In both phases, we can now go to the code than handles numerical - recursion or backreferences. */ + /* In both phases, for recursions, we can now go to the code than + handles numerical recursion. */ if (is_recurse) goto HANDLE_RECURSION; - else goto HANDLE_REFERENCE; + + /* In the second pass we must see if the name is duplicated. If so, we + generate a different opcode. */ + + if (lengthptr == NULL && cd->dupnames) + { + int count = 1; + unsigned int index = i; + pcre_uchar *cslot = slot + cd->name_entry_size; + + 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; + } + + if (count > 1) + { + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; + previous = code; + *code++ = ((options & PCRE_CASELESS) != 0)? OP_DNREFI : OP_DNREF; + PUT2INC(code, 0, index); + PUT2INC(code, 0, count); + + /* Process each potentially referenced group. */ + + for (; slot < cslot; slot += cd->name_entry_size) + { + open_capitem *oc; + recno = GET2(slot, 0); + cd->backref_map |= (recno < 32)? (1 << recno) : 1; + if (recno > cd->top_backref) cd->top_backref = recno; + + /* Check to see if this back reference is recursive, that it, it + is inside the group that it references. A flag is set so that the + group can be made atomic. */ + + for (oc = cd->open_caps; oc != NULL; oc = oc->next) + { + if (oc->number == recno) + { + oc->flag = TRUE; + break; + } + } + } + + continue; /* End of back ref handling */ + } + } + + /* First pass, or a non-duplicated name. */ + + goto HANDLE_REFERENCE; /* ------------------------------------------------------------ */ @@ -6302,7 +7192,7 @@ for (;; ptr++) while(IS_DIGIT(*ptr)) recno = recno * 10 + *ptr++ - CHAR_0; - if (*ptr != terminator) + if (*ptr != (pcre_uchar)terminator) { *errorcodeptr = ERR29; goto FAILED; @@ -6356,8 +7246,7 @@ for (;; ptr++) if (called == NULL) { - if (find_parens(cd, NULL, recno, - (options & PCRE_EXTENDED) != 0, utf) < 0) + if (recno > cd->final_bracount) { *errorcodeptr = ERR15; goto FAILED; @@ -6406,7 +7295,7 @@ for (;; ptr++) /* Can't determine a first byte now */ - if (firstchar == REQ_UNSET) firstchar = REQ_NONE; + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; continue; @@ -6516,10 +7405,19 @@ for (;; ptr++) skipbytes = IMM2_SIZE; } - /* Process nested bracketed regex. Assertions used not to be repeatable, - but this was changed for Perl compatibility, so all kinds can now be - repeated. We copy code into a non-register variable (tempcode) in order to - be able to pass its address because some compilers complain otherwise. */ + /* Process nested bracketed regex. First check for parentheses nested too + deeply. */ + + if ((cd->parens_depth += 1) > PARENS_NEST_LIMIT) + { + *errorcodeptr = ERR82; + goto FAILED; + } + + /* Assertions used not to be repeatable, but this was changed for Perl + compatibility, so all kinds can now be repeated. We copy code into a + non-register variable (tempcode) in order to be able to pass its address + because some compilers complain otherwise. */ previous = code; /* For handling repetition */ *code = bravalue; @@ -6540,7 +7438,9 @@ for (;; ptr++) cond_depth + ((bravalue == OP_COND)?1:0), /* Depth of condition subpatterns */ &subfirstchar, /* For possible first char */ + &subfirstcharflags, &subreqchar, /* For possible last char */ + &subreqcharflags, bcptr, /* Current branch chain */ cd, /* Tables block */ (lengthptr == NULL)? NULL : /* Actual compile phase */ @@ -6548,6 +7448,8 @@ for (;; ptr++) )) goto FAILED; + cd->parens_depth -= 1; + /* If this was an atomic group and there are no capturing groups within it, generate OP_ONCE_NC instead of OP_ONCE. */ @@ -6601,7 +7503,7 @@ for (;; ptr++) *errorcodeptr = ERR27; goto FAILED; } - if (condcount == 1) subfirstchar = subreqchar = REQ_NONE; + if (condcount == 1) subfirstcharflags = subreqcharflags = REQ_NONE; } } @@ -6650,7 +7552,9 @@ for (;; ptr++) back off. */ zeroreqchar = reqchar; + zeroreqcharflags = reqcharflags; zerofirstchar = firstchar; + zerofirstcharflags = firstcharflags; groupsetfirstchar = FALSE; if (bravalue >= OP_ONCE) @@ -6661,28 +7565,36 @@ for (;; ptr++) no firstchar, set "none" for the whole branch. In both cases, a zero repeat forces firstchar to "none". */ - if (firstchar == REQ_UNSET) + if (firstcharflags == REQ_UNSET) { - if (subfirstchar >= 0) + if (subfirstcharflags >= 0) { firstchar = subfirstchar; + firstcharflags = subfirstcharflags; groupsetfirstchar = TRUE; } - else firstchar = REQ_NONE; - zerofirstchar = REQ_NONE; + else firstcharflags = REQ_NONE; + zerofirstcharflags = REQ_NONE; } /* If firstchar was previously set, convert the subpattern's firstchar into reqchar if there wasn't one, using the vary flag that was in existence beforehand. */ - else if (subfirstchar >= 0 && subreqchar < 0) - subreqchar = subfirstchar | tempreqvary; + else if (subfirstcharflags >= 0 && subreqcharflags < 0) + { + subreqchar = subfirstchar; + subreqcharflags = subfirstcharflags | tempreqvary; + } /* If the subpattern set a required byte (or set a first byte that isn't really the first byte - see above), set it. */ - if (subreqchar >= 0) reqchar = subreqchar; + if (subreqcharflags >= 0) + { + reqchar = subreqchar; + reqcharflags = subreqcharflags; + } } /* For a forward assertion, we take the reqchar, if set. This can be @@ -6693,7 +7605,11 @@ for (;; ptr++) of a firstchar. This is overcome by a scan at the end if there's no firstchar, looking for an asserted first char. */ - else if (bravalue == OP_ASSERT && subreqchar >= 0) reqchar = subreqchar; + else if (bravalue == OP_ASSERT && subreqcharflags >= 0) + { + reqchar = subreqchar; + reqcharflags = subreqcharflags; + } break; /* End of processing '(' */ @@ -6701,19 +7617,21 @@ for (;; ptr++) /* Handle metasequences introduced by \. For ones like \d, the ESC_ values are arranged to be the negation of the corresponding OP_values in the default case when PCRE_UCP is not set. For the back references, the values - are ESC_REF plus the reference number. Only back references and those types + are negative the reference number. Only back references and those types that consume a character may be repeated. We can test for values between ESC_b and ESC_Z for the latter; this may have to change if any new ones are ever created. */ case CHAR_BACKSLASH: tempptr = ptr; - c = check_escape(&ptr, errorcodeptr, cd->bracount, options, FALSE); + escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options, FALSE); if (*errorcodeptr != 0) goto FAILED; - if (c < 0) + if (escape == 0) /* The escape coded a single character */ + c = ec; + else { - if (-c == ESC_Q) /* Handle start of quoted string */ + if (escape == ESC_Q) /* Handle start of quoted string */ { if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) ptr += 2; /* avoid empty string */ @@ -6721,71 +7639,60 @@ for (;; ptr++) continue; } - if (-c == ESC_E) continue; /* Perl ignores an orphan \E */ + if (escape == ESC_E) continue; /* Perl ignores an orphan \E */ /* For metasequences that actually match a character, we disable the setting of a first character if it hasn't already been set. */ - if (firstchar == REQ_UNSET && -c > ESC_b && -c < ESC_Z) - firstchar = REQ_NONE; + if (firstcharflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z) + firstcharflags = REQ_NONE; /* Set values to reset to if this is followed by a zero repeat. */ zerofirstchar = firstchar; + zerofirstcharflags = firstcharflags; zeroreqchar = reqchar; + zeroreqcharflags = reqcharflags; /* \g or \g'name' is a subroutine call by name and \g or \g'n' is a subroutine call by number (Oniguruma syntax). In fact, the value - -ESC_g is returned only for these cases. So we don't need to check for < - or ' if the value is -ESC_g. For the Perl syntax \g{n} the value is - -ESC_REF+n, and for the Perl syntax \g{name} the result is -ESC_k (as + ESC_g is returned only for these cases. So we don't need to check for < + or ' if the value is ESC_g. For the Perl syntax \g{n} the value is + -n, and for the Perl syntax \g{name} the result is ESC_k (as that is a synonym for a named back reference). */ - if (-c == ESC_g) + if (escape == ESC_g) { const pcre_uchar *p; + pcre_uint32 cf; + save_hwm = cd->hwm; /* Normally this is set when '(' is read */ terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; /* These two statements stop the compiler for warning about possibly unset variables caused by the jump to HANDLE_NUMERICAL_RECURSION. In - fact, because we actually check for a number below, the paths that + fact, because we do the check for a number below, the paths that would actually be in error are never taken. */ skipbytes = 0; reset_bracount = FALSE; - /* Test for a name */ + /* If it's not a signed or unsigned number, treat it as a name. */ - if (ptr[1] != CHAR_PLUS && ptr[1] != CHAR_MINUS) + cf = ptr[1]; + if (cf != CHAR_PLUS && cf != CHAR_MINUS && !IS_DIGIT(cf)) { - BOOL is_a_number = TRUE; - for (p = ptr + 1; *p != 0 && *p != terminator; p++) - { - if (!MAX_255(*p)) { is_a_number = FALSE; break; } - if ((cd->ctypes[*p] & ctype_digit) == 0) is_a_number = FALSE; - if ((cd->ctypes[*p] & ctype_word) == 0) break; - } - if (*p != terminator) - { - *errorcodeptr = ERR57; - break; - } - if (is_a_number) - { - ptr++; - goto HANDLE_NUMERICAL_RECURSION; - } is_recurse = TRUE; goto NAMED_REF_OR_RECURSE; } - /* Test a signed number in angle brackets or quotes. */ + /* Signed or unsigned number (cf = ptr[1]) is known to be plus or minus + or a digit. */ p = ptr + 2; while (IS_DIGIT(*p)) p++; - if (*p != terminator) + if (*p != (pcre_uchar)terminator) { *errorcodeptr = ERR57; break; @@ -6797,7 +7704,7 @@ for (;; ptr++) /* \k or \k'name' is a back reference by name (Perl syntax). We also support \k{name} (.NET syntax). */ - if (-c == ESC_k) + if (escape == ESC_k) { if ((ptr[1] != CHAR_LESS_THAN_SIGN && ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET)) @@ -6816,13 +7723,16 @@ for (;; ptr++) not set to cope with cases like (?=(\w+))\1: which would otherwise set ':' later. */ - if (-c >= ESC_REF) + if (escape < 0) { open_capitem *oc; - recno = -c - ESC_REF; + recno = -escape; - HANDLE_REFERENCE: /* Come here from named backref handling */ - if (firstchar == REQ_UNSET) firstchar = REQ_NONE; + /* Come here from named backref handling when the reference is to a + single group (i.e. not to a duplicated name. */ + + HANDLE_REFERENCE: + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; previous = code; *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF; PUT2INC(code, 0, recno); @@ -6846,14 +7756,14 @@ for (;; ptr++) /* So are Unicode property matches, if supported. */ #ifdef SUPPORT_UCP - else if (-c == ESC_P || -c == ESC_p) + else if (escape == ESC_P || escape == ESC_p) { BOOL negated; - int pdata; - int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr); - if (ptype < 0) goto FAILED; + unsigned int ptype = 0, pdata = 0; + if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr)) + goto FAILED; previous = code; - *code++ = ((-c == ESC_p) != negated)? OP_PROP : OP_NOTPROP; + *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP; *code++ = ptype; *code++ = pdata; } @@ -6862,7 +7772,7 @@ for (;; ptr++) /* If Unicode properties are not supported, \X, \P, and \p are not allowed. */ - else if (-c == ESC_X || -c == ESC_P || -c == ESC_p) + else if (escape == ESC_X || escape == ESC_P || escape == ESC_p) { *errorcodeptr = ERR45; goto FAILED; @@ -6873,17 +7783,18 @@ for (;; ptr++) can obtain the OP value by negating the escape value in the default situation when PCRE_UCP is not set. When it *is* set, we substitute Unicode property tests. Note that \b and \B do a one-character - lookbehind. */ + lookbehind, and \A also behaves as if it does. */ else { - if ((-c == ESC_b || -c == ESC_B) && cd->max_lookbehind == 0) + if ((escape == ESC_b || escape == ESC_B || escape == ESC_A) && + cd->max_lookbehind == 0) cd->max_lookbehind = 1; #ifdef SUPPORT_UCP - if (-c >= ESC_DU && -c <= ESC_wu) + if (escape >= ESC_DU && escape <= ESC_wu) { nestptr = ptr + 1; /* Where to resume */ - ptr = substitutes[-c - ESC_DU] - 1; /* Just before substitute */ + ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ } else #endif @@ -6891,8 +7802,8 @@ for (;; ptr++) so that it works in DFA mode and in lookbehinds. */ { - previous = (-c > ESC_b && -c < ESC_Z)? code : NULL; - *code++ = (!utf && c == -ESC_C)? OP_ALLANY : -c; + previous = (escape > ESC_b && escape < ESC_Z)? code : NULL; + *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape; } } continue; @@ -6902,7 +7813,7 @@ for (;; ptr++) a value > 127. We set its representation in the length/buffer, and then handle it as a data character. */ -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR) mclength = PRIV(ord2utf)(c, mcbuffer); else @@ -6917,8 +7828,8 @@ for (;; ptr++) /* ===================================================================*/ /* Handle a literal character. It is guaranteed not to be whitespace or # - when the extended flag is set. If we are in UTF-8 mode, it may be a - multi-byte literal character. */ + when the extended flag is set. If we are in a UTF mode, it may be a + multi-unit literal character. */ default: NORMAL_CHAR: @@ -6935,6 +7846,29 @@ for (;; ptr++) ONE_CHAR: previous = code; + + /* 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 + OP_PROP item instead of OP_CHARI. */ + +#ifdef SUPPORT_UCP + if (utf && (options & PCRE_CASELESS) != 0) + { + GETCHAR(c, mcbuffer); + if ((c = UCD_CASESET(c)) != 0) + { + *code++ = OP_PROP; + *code++ = PT_CLIST; + *code++ = c; + if (firstcharflags == REQ_UNSET) + firstcharflags = zerofirstcharflags = REQ_NONE; + break; + } + } +#endif + + /* Caseful matches, or not one of the multicase characters. */ + *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARI : OP_CHAR; for (c = 0; c < mclength; c++) *code++ = mcbuffer[c]; @@ -6948,10 +7882,11 @@ for (;; ptr++) Otherwise, leave the firstchar value alone, and don't change it on a zero repeat. */ - if (firstchar == REQ_UNSET) + if (firstcharflags == REQ_UNSET) { - zerofirstchar = REQ_NONE; + zerofirstcharflags = REQ_NONE; zeroreqchar = reqchar; + zeroreqcharflags = reqcharflags; /* If the character is more than one byte long, we can set firstchar only if it is not to be matched caselessly. */ @@ -6959,9 +7894,16 @@ for (;; ptr++) if (mclength == 1 || req_caseopt == 0) { firstchar = mcbuffer[0] | req_caseopt; - if (mclength != 1) reqchar = code[-1] | cd->req_varyopt; + firstchar = mcbuffer[0]; + firstcharflags = req_caseopt; + + if (mclength != 1) + { + reqchar = code[-1]; + reqcharflags = cd->req_varyopt; + } } - else firstchar = reqchar = REQ_NONE; + else firstcharflags = reqcharflags = REQ_NONE; } /* firstchar was previously set; we can set reqchar only if the length is @@ -6970,9 +7912,14 @@ for (;; ptr++) else { zerofirstchar = firstchar; + zerofirstcharflags = firstcharflags; zeroreqchar = reqchar; + zeroreqcharflags = reqcharflags; if (mclength == 1 || req_caseopt == 0) - reqchar = code[-1] | req_caseopt | cd->req_varyopt; + { + reqchar = code[-1]; + reqcharflags = req_caseopt | cd->req_varyopt; + } } break; /* End of literal character handling */ @@ -6991,7 +7938,6 @@ return FALSE; - /************************************************* * Compile sequence of alternatives * *************************************************/ @@ -7004,28 +7950,32 @@ out the amount of memory needed, as well as during the real compile phase. The value of lengthptr distinguishes the two phases. Arguments: - options option bits, including any changes for this subpattern - codeptr -> the address of the current code pointer - ptrptr -> the address of the current pattern pointer - errorcodeptr -> pointer to error code variable - lookbehind TRUE if this is a lookbehind assertion - reset_bracount TRUE to reset the count for each branch - skipbytes skip this many bytes at start (for brackets and OP_COND) - cond_depth depth of nesting for conditional subpatterns - firstcharptr place to put the first required character, or a negative number - reqcharptr place to put the last required character, or a negative number - bcptr pointer to the chain of currently open branches - cd points to the data block with tables pointers etc. - lengthptr NULL during the real compile phase - points to length accumulator during pre-compile phase + options option bits, including any changes for this subpattern + codeptr -> the address of the current code pointer + ptrptr -> the address of the current pattern pointer + errorcodeptr -> pointer to error code variable + lookbehind TRUE if this is a lookbehind assertion + reset_bracount TRUE to reset the count for each branch + skipbytes skip this many bytes at start (for brackets and OP_COND) + cond_depth depth of nesting for conditional subpatterns + firstcharptr place to put the first required character + firstcharflagsptr place to put the first character flags, or a negative number + reqcharptr place to put the last required character + reqcharflagsptr place to put the last required character flags, or a negative number + bcptr pointer to the chain of currently open branches + cd points to the data block with tables pointers etc. + lengthptr NULL during the real compile phase + points to length accumulator during pre-compile phase -Returns: TRUE on success +Returns: TRUE on success */ static BOOL compile_regex(int options, pcre_uchar **codeptr, const pcre_uchar **ptrptr, int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, int skipbytes, - int cond_depth, pcre_int32 *firstcharptr, pcre_int32 *reqcharptr, + int cond_depth, + pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr, + pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr, branch_chain *bcptr, compile_data *cd, int *lengthptr) { const pcre_uchar *ptr = *ptrptr; @@ -7035,17 +7985,20 @@ pcre_uchar *start_bracket = code; pcre_uchar *reverse_count = NULL; open_capitem capitem; int capnumber = 0; -pcre_int32 firstchar, reqchar; -pcre_int32 branchfirstchar, branchreqchar; +pcre_uint32 firstchar, reqchar; +pcre_int32 firstcharflags, reqcharflags; +pcre_uint32 branchfirstchar, branchreqchar; +pcre_int32 branchfirstcharflags, branchreqcharflags; int length; -int orig_bracount; -int max_bracount; +unsigned int orig_bracount; +unsigned int max_bracount; branch_chain bc; bc.outer = bcptr; bc.current_branch = code; -firstchar = reqchar = REQ_UNSET; +firstchar = reqchar = 0; +firstcharflags = reqcharflags = REQ_UNSET; /* Accumulate the length for use in the pre-compile phase. Start with the length of the BRA and KET and any extra bytes that are required at the @@ -7105,8 +8058,8 @@ for (;;) into the length. */ if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstchar, - &branchreqchar, &bc, cond_depth, cd, - (lengthptr == NULL)? NULL : &length)) + &branchfirstcharflags, &branchreqchar, &branchreqcharflags, &bc, + cond_depth, cd, (lengthptr == NULL)? NULL : &length)) { *ptrptr = ptr; return FALSE; @@ -7127,7 +8080,9 @@ for (;;) if (*last_branch != OP_ALT) { firstchar = branchfirstchar; + firstcharflags = branchfirstcharflags; reqchar = branchreqchar; + reqcharflags = branchreqcharflags; } /* If this is not the first branch, the first char and reqchar have to @@ -7141,23 +8096,36 @@ for (;;) we have to abandon the firstchar for the regex, but if there was previously no reqchar, it takes on the value of the old firstchar. */ - if (firstchar >= 0 && firstchar != branchfirstchar) + if (firstcharflags >= 0 && + (firstcharflags != branchfirstcharflags || firstchar != branchfirstchar)) { - if (reqchar < 0) reqchar = firstchar; - firstchar = REQ_NONE; + if (reqcharflags < 0) + { + reqchar = firstchar; + reqcharflags = firstcharflags; + } + firstcharflags = REQ_NONE; } /* If we (now or from before) have no firstchar, a firstchar from the branch becomes a reqchar if there isn't a branch reqchar. */ - if (firstchar < 0 && branchfirstchar >= 0 && branchreqchar < 0) - branchreqchar = branchfirstchar; + if (firstcharflags < 0 && branchfirstcharflags >= 0 && branchreqcharflags < 0) + { + branchreqchar = branchfirstchar; + branchreqcharflags = branchfirstcharflags; + } /* Now ensure that the reqchars match */ - if ((reqchar & ~REQ_VARY) != (branchreqchar & ~REQ_VARY)) - reqchar = REQ_NONE; - else reqchar |= branchreqchar; /* To "or" REQ_VARY */ + if (((reqcharflags & ~REQ_VARY) != (branchreqcharflags & ~REQ_VARY)) || + reqchar != branchreqchar) + reqcharflags = REQ_NONE; + else + { + reqchar = branchreqchar; + reqcharflags |= branchreqcharflags; /* To "or" REQ_VARY */ + } } /* If lookbehind, check that this branch matches a fixed-length string, and @@ -7253,7 +8221,9 @@ for (;;) *codeptr = code; *ptrptr = ptr; *firstcharptr = firstchar; + *firstcharflagsptr = firstcharflags; *reqcharptr = reqchar; + *reqcharflagsptr = reqcharflags; if (lengthptr != NULL) { if (OFLOW_MAX - *lengthptr < length) @@ -7323,19 +8293,23 @@ and the highest back reference was greater than or equal to that level. However, by keeping a bitmap of the first 31 back references, we can catch some of the more common cases more precisely. +... A second exception is when the .* appears inside an atomic group, because +this prevents the number of characters it matches from being adjusted. + Arguments: code points to start of expression (the bracket) bracket_map a bitmap of which brackets we are inside while testing; this handles up to substring 31; after that we just have to take the less precise approach - backref_map the back reference bitmap + cd points to the compile data block + atomcount atomic group level Returns: TRUE or FALSE */ static BOOL is_anchored(register const pcre_uchar *code, unsigned int bracket_map, - unsigned int backref_map) + compile_data *cd, int atomcount) { do { const pcre_uchar *scode = first_significant_code( @@ -7347,7 +8321,7 @@ do { if (op == OP_BRA || op == OP_BRAPOS || op == OP_SBRA || op == OP_SBRAPOS) { - if (!is_anchored(scode, bracket_map, backref_map)) return FALSE; + if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE; } /* Capturing brackets */ @@ -7357,30 +8331,40 @@ do { { int n = GET2(scode, 1+LINK_SIZE); int new_map = bracket_map | ((n < 32)? (1 << n) : 1); - if (!is_anchored(scode, new_map, backref_map)) return FALSE; + if (!is_anchored(scode, new_map, cd, atomcount)) return FALSE; } - /* Other brackets */ + /* Positive forward assertions and conditions */ - else if (op == OP_ASSERT || op == OP_ONCE || op == OP_ONCE_NC || - op == OP_COND) + else if (op == OP_ASSERT || op == OP_COND) { - if (!is_anchored(scode, bracket_map, backref_map)) return FALSE; + if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE; + } + + /* Atomic groups */ + + else if (op == OP_ONCE || op == OP_ONCE_NC) + { + if (!is_anchored(scode, bracket_map, cd, atomcount + 1)) + return FALSE; } /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and - it isn't in brackets that are or may be referenced. */ + it isn't in brackets that are or may be referenced or inside an atomic + group. */ else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)) { - if (scode[1] != OP_ALLANY || (bracket_map & backref_map) != 0) + if (scode[1] != OP_ALLANY || (bracket_map & cd->backref_map) != 0 || + atomcount > 0 || cd->had_pruneorskip) return FALSE; } /* Check for explicit anchoring */ else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE; + code += GET(code, 1); } while (*code == OP_ALT); /* Loop for each alternative */ @@ -7398,21 +8382,24 @@ return TRUE; matching and for non-DOTALL patterns that start with .* (which must start at the beginning or after \n). As in the case of is_anchored() (see above), we have to take account of back references to capturing brackets that contain .* -because in that case we can't make the assumption. +because in that case we can't make the assumption. Also, the appearance of .* +inside atomic brackets or in a pattern that contains *PRUNE or *SKIP does not +count, because once again the assumption no longer holds. Arguments: code points to start of expression (the bracket) bracket_map a bitmap of which brackets we are inside while testing; this handles up to substring 31; after that we just have to take the less precise approach - backref_map the back reference bitmap + cd points to the compile data + atomcount atomic group level Returns: TRUE or FALSE */ static BOOL is_startline(const pcre_uchar *code, unsigned int bracket_map, - unsigned int backref_map) + compile_data *cd, int atomcount) { do { const pcre_uchar *scode = first_significant_code( @@ -7431,14 +8418,14 @@ do { switch (*scode) { case OP_CREF: - case OP_NCREF: + case OP_DNCREF: case OP_RREF: - case OP_NRREF: + case OP_DNRREF: case OP_DEF: return FALSE; default: /* Assertion */ - if (!is_startline(scode, bracket_map, backref_map)) return FALSE; + if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE; do scode += GET(scode, 1); while (*scode == OP_ALT); scode += 1 + LINK_SIZE; break; @@ -7452,7 +8439,7 @@ do { if (op == OP_BRA || op == OP_BRAPOS || op == OP_SBRA || op == OP_SBRAPOS) { - if (!is_startline(scode, bracket_map, backref_map)) return FALSE; + if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE; } /* Capturing brackets */ @@ -7462,25 +8449,40 @@ do { { int n = GET2(scode, 1+LINK_SIZE); int new_map = bracket_map | ((n < 32)? (1 << n) : 1); - if (!is_startline(scode, new_map, backref_map)) return FALSE; + if (!is_startline(scode, new_map, cd, atomcount)) return FALSE; } - /* Other brackets */ + /* Positive forward assertions */ - else if (op == OP_ASSERT || op == OP_ONCE || op == OP_ONCE_NC) + else if (op == OP_ASSERT) { - if (!is_startline(scode, bracket_map, backref_map)) return FALSE; + if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE; } - /* .* means "start at start or after \n" if it isn't in brackets that - may be referenced. */ + /* Atomic brackets */ + + else if (op == OP_ONCE || op == OP_ONCE_NC) + { + if (!is_startline(scode, bracket_map, cd, atomcount + 1)) return FALSE; + } + + /* .* means "start at start or after \n" if it isn't in atomic brackets or + brackets that may be referenced, as long as the pattern does not contain + *PRUNE or *SKIP, because these break the feature. Consider, for example, + /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e. not at the + start of a line. */ else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) { - if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE; + if (scode[1] != OP_ANY || (bracket_map & cd->backref_map) != 0 || + atomcount > 0 || cd->had_pruneorskip) + return FALSE; } - /* Check for explicit circumflex */ + /* Check for explicit circumflex; anything else gives a FALSE result. Note + in particular that this includes atomic brackets OP_ONCE and OP_ONCE_NC + because the number of characters matched by .* cannot be adjusted inside + them. */ else if (op != OP_CIRC && op != OP_CIRCM) return FALSE; @@ -7502,33 +8504,40 @@ return TRUE; discarded, because they can cause conflicts with actual literals that follow. However, if we end up without a first char setting for an unanchored pattern, it is worth scanning the regex to see if there is an initial asserted first -char. If all branches start with the same asserted char, or with a bracket all -of whose alternatives start with the same asserted char (recurse ad lib), then -we return that char, otherwise -1. +char. If all branches start with the same asserted char, or with a +non-conditional bracket all of whose alternatives start with the same asserted +char (recurse ad lib), then we return that char, with the flags set to zero or +REQ_CASELESS; otherwise return zero with REQ_NONE in the flags. Arguments: code points to start of expression (the bracket) + flags points to the first char flags, or to REQ_NONE inassert TRUE if in an assertion -Returns: -1 or the fixed first char +Returns: the fixed first char, or 0 with REQ_NONE in flags */ -static int -find_firstassertedchar(const pcre_uchar *code, BOOL inassert) +static pcre_uint32 +find_firstassertedchar(const pcre_uchar *code, pcre_int32 *flags, + BOOL inassert) { -register int c = -1; +register pcre_uint32 c = 0; +int cflags = REQ_NONE; + +*flags = REQ_NONE; do { - int d; + pcre_uint32 d; + int dflags; int xl = (*code == OP_CBRA || *code == OP_SCBRA || *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0; const pcre_uchar *scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE); - register int op = *scode; + register pcre_uchar op = *scode; switch(op) { default: - return -1; + return 0; case OP_BRA: case OP_BRAPOS: @@ -7539,10 +8548,10 @@ do { case OP_ASSERT: case OP_ONCE: case OP_ONCE_NC: - case OP_COND: - if ((d = find_firstassertedchar(scode, op == OP_ASSERT)) < 0) - return -1; - if (c < 0) c = d; else if (c != d) return -1; + d = find_firstassertedchar(scode, &dflags, op == OP_ASSERT); + if (dflags < 0) + return 0; + if (cflags < 0) { c = d; cflags = dflags; } else if (c != d || cflags != dflags) return 0; break; case OP_EXACT: @@ -7553,9 +8562,9 @@ do { case OP_PLUS: case OP_MINPLUS: case OP_POSPLUS: - if (!inassert) return -1; - if (c < 0) c = scode[1]; - else if (c != scode[1]) return -1; + if (!inassert) return 0; + if (cflags < 0) { c = scode[1]; cflags = 0; } + else if (c != scode[1]) return 0; break; case OP_EXACTI: @@ -7566,20 +8575,77 @@ do { case OP_PLUSI: case OP_MINPLUSI: case OP_POSPLUSI: - if (!inassert) return -1; - if (c < 0) c = scode[1] | REQ_CASELESS; - else if (c != scode[1]) return -1; + if (!inassert) return 0; + if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; } + else if (c != scode[1]) return 0; break; } code += GET(code, 1); } while (*code == OP_ALT); + +*flags = cflags; return c; } +/************************************************* +* Add an entry to the name/number table * +*************************************************/ + +/* This function is called between compiling passes to add an entry to the +name/number table, maintaining alphabetical order. Checking for permitted +and forbidden duplicates has already been done. + +Arguments: + cd the compile data block + name the name to add + length the length of the name + groupno the group number + +Returns: nothing +*/ + +static void +add_name(compile_data *cd, const pcre_uchar *name, int length, + unsigned int groupno) +{ +int i; +pcre_uchar *slot = cd->name_table; + +for (i = 0; i < cd->names_found; i++) + { + int crc = memcmp(name, slot+IMM2_SIZE, IN_UCHARS(length)); + if (crc == 0 && slot[IMM2_SIZE+length] != 0) + crc = -1; /* Current name is a substring */ + + /* Make space in the table and break the loop for an earlier name. For a + duplicate or later name, carry on. We do this for duplicates so that in the + simple case (when ?(| is not used) they are in order of their numbers. In all + cases they are in the order in which they appear in the pattern. */ + + if (crc < 0) + { + memmove(slot + cd->name_entry_size, slot, + IN_UCHARS((cd->names_found - i) * cd->name_entry_size)); + break; + } + + /* Continue the loop for a later or duplicate name */ + + slot += cd->name_entry_size; + } + +PUT2(slot, 0, groupno); +memcpy(slot + IMM2_SIZE, name, IN_UCHARS(length)); +slot[IMM2_SIZE + length] = 0; +cd->names_found++; +} + + + /************************************************* * Compile a Regular Expression * *************************************************/ @@ -7602,41 +8668,55 @@ Returns: pointer to compiled data block, or NULL on error, with errorptr and erroroffset set */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION pcre_compile(const char *pattern, int options, const char **errorptr, int *erroroffset, const unsigned char *tables) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION pcre16_compile(PCRE_SPTR16 pattern, int options, const char **errorptr, int *erroroffset, const unsigned char *tables) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION +pcre32_compile(PCRE_SPTR32 pattern, int options, const char **errorptr, + int *erroroffset, const unsigned char *tables) #endif { -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables); -#else +#elif defined COMPILE_PCRE16 return pcre16_compile2(pattern, options, NULL, errorptr, erroroffset, tables); +#elif defined COMPILE_PCRE32 +return pcre32_compile2(pattern, options, NULL, errorptr, erroroffset, tables); #endif } -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION pcre_compile2(const char *pattern, int options, int *errorcodeptr, const char **errorptr, int *erroroffset, const unsigned char *tables) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION pcre16_compile2(PCRE_SPTR16 pattern, int options, int *errorcodeptr, const char **errorptr, int *erroroffset, const unsigned char *tables) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION +pcre32_compile2(PCRE_SPTR32 pattern, int options, int *errorcodeptr, + const char **errorptr, int *erroroffset, const unsigned char *tables) #endif { REAL_PCRE *re; int length = 1; /* For final END opcode */ -pcre_int32 firstchar, reqchar; +pcre_int32 firstcharflags, reqcharflags; +pcre_uint32 firstchar, reqchar; +pcre_uint32 limit_match = PCRE_UINT32_MAX; +pcre_uint32 limit_recursion = PCRE_UINT32_MAX; int newline; int errorcode = 0; int skipatstart = 0; BOOL utf; +BOOL never_utf = FALSE; size_t size; pcre_uchar *code; const pcre_uchar *codestart; @@ -7653,6 +8733,11 @@ new memory is obtained from malloc(). */ pcre_uchar cworkspace[COMPILE_WORK_SIZE]; +/* This vector is used for remembering name groups during the pre-compile. In a +similar way to cworkspace, it can be expanded using malloc() if necessary. */ + +named_group named_groups[NAMED_GROUP_LIST_SIZE]; + /* Set this early so that early errors get offset 0. */ ptr = (const pcre_uchar *)pattern; @@ -7696,28 +8781,85 @@ if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0) goto PCRE_EARLY_ERROR_RETURN; } +/* If PCRE_NEVER_UTF is set, remember it. */ + +if ((options & PCRE_NEVER_UTF) != 0) never_utf = TRUE; + /* Check for global one-time settings at the start of the pattern, and remember the offset for later. */ +cd->external_flags = 0; /* Initialize here for LIMIT_MATCH/RECURSION */ + while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && ptr[skipatstart+1] == CHAR_ASTERISK) { int newnl = 0; int newbsr = 0; +/* For completeness and backward compatibility, (*UTFn) is supported in the +relevant libraries, but (*UTF) is generic and always supported. Note that +PCRE_UTF8 == PCRE_UTF16 == PCRE_UTF32. */ + #ifdef COMPILE_PCRE8 - if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_RIGHTPAR, 5) == 0) + if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF8_RIGHTPAR, 5) == 0) { skipatstart += 7; options |= PCRE_UTF8; continue; } #endif #ifdef COMPILE_PCRE16 - if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_RIGHTPAR, 6) == 0) + if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF16_RIGHTPAR, 6) == 0) { skipatstart += 8; options |= PCRE_UTF16; continue; } #endif +#ifdef COMPILE_PCRE32 + if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF32_RIGHTPAR, 6) == 0) + { skipatstart += 8; options |= PCRE_UTF32; continue; } +#endif + + else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_RIGHTPAR, 4) == 0) + { skipatstart += 6; options |= PCRE_UTF8; continue; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UCP_RIGHTPAR, 4) == 0) { skipatstart += 6; options |= PCRE_UCP; continue; } + else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_NO_AUTO_POSSESS_RIGHTPAR, 16) == 0) + { skipatstart += 18; options |= PCRE_NO_AUTO_POSSESS; continue; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_NO_START_OPT_RIGHTPAR, 13) == 0) { skipatstart += 15; options |= PCRE_NO_START_OPTIMIZE; continue; } + else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_MATCH_EQ, 12) == 0) + { + pcre_uint32 c = 0; + int p = skipatstart + 14; + while (isdigit(ptr[p])) + { + if (c > PCRE_UINT32_MAX / 10 - 1) break; /* Integer overflow */ + c = c*10 + ptr[p++] - CHAR_0; + } + if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break; + if (c < limit_match) + { + limit_match = c; + cd->external_flags |= PCRE_MLSET; + } + skipatstart = p; + continue; + } + + else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_RECURSION_EQ, 16) == 0) + { + pcre_uint32 c = 0; + int p = skipatstart + 18; + while (isdigit(ptr[p])) + { + if (c > PCRE_UINT32_MAX / 10 - 1) break; /* Integer overflow check */ + c = c*10 + ptr[p++] - CHAR_0; + } + if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break; + if (c < limit_recursion) + { + limit_recursion = c; + cd->external_flags |= PCRE_RLSET; + } + skipatstart = p; + continue; + } + if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_CR_RIGHTPAR, 3) == 0) { skipatstart += 5; newnl = PCRE_NEWLINE_CR; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LF_RIGHTPAR, 3) == 0) @@ -7741,8 +8883,13 @@ while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && else break; } -/* PCRE_UTF16 has the same value as PCRE_UTF8. */ +/* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */ utf = (options & PCRE_UTF8) != 0; +if (utf && never_utf) + { + errorcode = ERR78; + goto PCRE_EARLY_ERROR_RETURN2; + } /* Can't support UTF unless PCRE has been compiled to include the code. The return of an error code from PRIV(valid_utf)() is a new feature, introduced in @@ -7753,10 +8900,12 @@ not used here. */ if (utf && (options & PCRE_NO_UTF8_CHECK) == 0 && (errorcode = PRIV(valid_utf)((PCRE_PUCHAR)pattern, -1, erroroffset)) != 0) { -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 errorcode = ERR44; -#else +#elif defined COMPILE_PCRE16 errorcode = ERR74; +#elif defined COMPILE_PCRE32 + errorcode = ERR77; #endif goto PCRE_EARLY_ERROR_RETURN2; } @@ -7853,17 +9002,21 @@ cd->bracount = cd->final_bracount = 0; cd->names_found = 0; cd->name_entry_size = 0; cd->name_table = NULL; +cd->dupnames = FALSE; +cd->namedrefcount = 0; cd->start_code = cworkspace; cd->hwm = cworkspace; cd->start_workspace = cworkspace; cd->workspace_size = COMPILE_WORK_SIZE; +cd->named_groups = named_groups; +cd->named_group_list_size = NAMED_GROUP_LIST_SIZE; cd->start_pattern = (const pcre_uchar *)pattern; cd->end_pattern = (const pcre_uchar *)(pattern + STRLEN_UC((const pcre_uchar *)pattern)); cd->req_varyopt = 0; +cd->parens_depth = 0; cd->assert_depth = 0; cd->max_lookbehind = 0; cd->external_options = options; -cd->external_flags = 0; cd->open_caps = NULL; /* Now do the pre-compile. On error, errorcode will be set non-zero, so we @@ -7875,8 +9028,10 @@ outside can help speed up starting point checks. */ ptr += skipatstart; code = cworkspace; *code = OP_BRA; + (void)compile_regex(cd->external_options, &code, &ptr, &errorcode, FALSE, - FALSE, 0, 0, &firstchar, &reqchar, NULL, cd, &length); + FALSE, 0, 0, &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL, + cd, &length); if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN; DPRINTF(("end pre-compile: length=%d workspace=%d\n", length, @@ -7888,14 +9043,23 @@ if (length > MAX_PATTERN_SIZE) goto PCRE_EARLY_ERROR_RETURN; } -/* Compute the size of data block needed and get it, either from malloc or -externally provided function. Integer overflow should no longer be possible -because nowadays we limit the maximum value of cd->names_found and -cd->name_entry_size. */ +/* If there are groups with duplicate names and there are also references by +name, we must allow for the possibility of named references to duplicated +groups. These require an extra data item each. */ + +if (cd->dupnames && cd->namedrefcount > 0) + length += cd->namedrefcount * IMM2_SIZE * sizeof(pcre_uchar); + +/* Compute the size of the data block for storing the compiled pattern. Integer +overflow should no longer be possible because nowadays we limit the maximum +value of cd->names_found and cd->name_entry_size. */ + +size = sizeof(REAL_PCRE) + + (length + cd->names_found * cd->name_entry_size) * sizeof(pcre_uchar); + +/* Get the memory. */ -size = sizeof(REAL_PCRE) + (length + cd->names_found * cd->name_entry_size) * sizeof(pcre_uchar); re = (REAL_PCRE *)(PUBL(malloc))(size); - if (re == NULL) { errorcode = ERR21; @@ -7912,6 +9076,8 @@ re->magic_number = MAGIC_NUMBER; re->size = (int)size; re->options = cd->external_options; re->flags = cd->external_flags; +re->limit_match = limit_match; +re->limit_recursion = limit_recursion; re->first_char = 0; re->req_char = 0; re->name_table_offset = sizeof(REAL_PCRE) / sizeof(pcre_uchar); @@ -7920,6 +9086,11 @@ re->name_count = cd->names_found; re->ref_count = 0; re->tables = (tables == PRIV(default_tables))? NULL : tables; re->nullpad = NULL; +#ifdef COMPILE_PCRE32 +re->dummy = 0; +#else +re->dummy1 = re->dummy2 = re->dummy3 = 0; +#endif /* The starting points of the name/number translation table and of the code are passed around in the compile data block. The start/end pattern and initial @@ -7929,19 +9100,34 @@ field; this time it's used for remembering forward references to subpatterns. */ cd->final_bracount = cd->bracount; /* Save for checking forward references */ +cd->parens_depth = 0; cd->assert_depth = 0; cd->bracount = 0; cd->max_lookbehind = 0; -cd->names_found = 0; cd->name_table = (pcre_uchar *)re + re->name_table_offset; codestart = cd->name_table + re->name_entry_size * re->name_count; cd->start_code = codestart; cd->hwm = (pcre_uchar *)(cd->start_workspace); cd->req_varyopt = 0; cd->had_accept = FALSE; +cd->had_pruneorskip = FALSE; cd->check_lookbehind = FALSE; cd->open_caps = NULL; +/* If any named groups were found, create the name/number table from the list +created in the first pass. */ + +if (cd->names_found > 0) + { + int i = cd->names_found; + named_group *ng = cd->named_groups; + cd->names_found = 0; + for (; i > 0; i--, ng++) + add_name(cd, ng->name, ng->length, ng->number); + if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE) + (PUBL(free))((void *)cd->named_groups); + } + /* Set up a starting, non-extracting bracket, then compile the expression. On error, errorcode will be set non-zero, so we don't need to look at the result of the function here. */ @@ -7950,17 +9136,21 @@ ptr = (const pcre_uchar *)pattern + skipatstart; code = (pcre_uchar *)codestart; *code = OP_BRA; (void)compile_regex(re->options, &code, &ptr, &errorcode, FALSE, FALSE, 0, 0, - &firstchar, &reqchar, NULL, cd, NULL); + &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL, cd, NULL); re->top_bracket = cd->bracount; re->top_backref = cd->top_backref; re->max_lookbehind = cd->max_lookbehind; re->flags = cd->external_flags | PCRE_MODE; -if (cd->had_accept) reqchar = REQ_NONE; /* Must disable after (*ACCEPT) */ +if (cd->had_accept) + { + reqchar = 0; /* Must disable after (*ACCEPT) */ + reqcharflags = REQ_NONE; + } /* If not reached end of pattern on success, there's an excess bracket. */ -if (errorcode == 0 && *ptr != 0) errorcode = ERR22; +if (errorcode == 0 && *ptr != CHAR_NULL) errorcode = ERR22; /* Fill in the terminating state and check for disastrous overflow, but if debugging, leave the test till after things are printed out. */ @@ -7971,6 +9161,13 @@ if debugging, leave the test till after things are printed out. */ if (code - codestart > length) errorcode = ERR23; #endif +#ifdef SUPPORT_VALGRIND +/* If the estimated length exceeds the really used length, mark the extra +allocated memory as unaddressable, so that any out-of-bound reads can be +detected. */ +VALGRIND_MAKE_MEM_NOACCESS(code, (length - (code - codestart)) * sizeof(pcre_uchar)); +#endif + /* Fill in any forward references that are required. There may be repeated references; optimize for them, as searching a large regex takes time. */ @@ -7994,19 +9191,27 @@ if (cd->hwm > cd->start_workspace) } } -/* If the workspace had to be expanded, free the new memory. */ +/* If the workspace had to be expanded, free the new memory. Set the pointer to +NULL to indicate that forward references have been filled in. */ if (cd->workspace_size > COMPILE_WORK_SIZE) (PUBL(free))((void *)cd->start_workspace); +cd->start_workspace = NULL; /* Give an error if there's back reference to a non-existent capturing subpattern. */ if (errorcode == 0 && re->top_backref > re->top_bracket) errorcode = ERR15; +/* Unless disabled, check whether single character iterators can be +auto-possessified. The function overwrites the appropriate opcode values. */ + +if ((options & PCRE_NO_AUTO_POSSESS) == 0) + auto_possessify((pcre_uchar *)codestart, utf, cd); + /* If there were any lookbehind assertions that contained OP_RECURSE (recursions or subroutine calls), a flag is set for them to be checked here, -because they may contain forward references. Actual recursions can't be fixed +because they may contain forward references. Actual recursions cannot be fixed length, but subroutine calls can. It is done like this so that those without OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The exceptional ones forgo this. We scan the pattern to check that they are fixed @@ -8062,33 +9267,33 @@ if (errorcode != 0) } /* If the anchored option was not passed, set the flag if we can determine that -the pattern is anchored by virtue of ^ characters or \A or anything else (such -as starting with .* when DOTALL is set). +the pattern is anchored by virtue of ^ characters or \A or anything else, such +as starting with non-atomic .* when DOTALL is set and there are no occurrences +of *PRUNE or *SKIP. Otherwise, if we know what the first byte has to be, save it, because that speeds up unanchored matches no end. If not, see if we can set the PCRE_STARTLINE flag. This is helpful for multiline matches when all branches -start with ^. and also when all branches start with .* for non-DOTALL matches. -*/ +start with ^. and also when all branches start with non-atomic .* for +non-DOTALL matches when *PRUNE and SKIP are not present. */ if ((re->options & PCRE_ANCHORED) == 0) { - if (is_anchored(codestart, 0, cd->backref_map)) - re->options |= PCRE_ANCHORED; + if (is_anchored(codestart, 0, cd, 0)) re->options |= PCRE_ANCHORED; else { - if (firstchar < 0) - firstchar = find_firstassertedchar(codestart, FALSE); - if (firstchar >= 0) /* Remove caseless flag for non-caseable chars */ + if (firstcharflags < 0) + firstchar = find_firstassertedchar(codestart, &firstcharflags, FALSE); + if (firstcharflags >= 0) /* Remove caseless flag for non-caseable chars */ { -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 re->first_char = firstchar & 0xff; -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 re->first_char = firstchar & 0xffff; +#elif defined COMPILE_PCRE32 + re->first_char = firstchar; #endif -#endif - if ((firstchar & REQ_CASELESS) != 0) + if ((firstcharflags & REQ_CASELESS) != 0) { #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8) /* We ignore non-ASCII first chars in 8 bit mode. */ @@ -8111,8 +9316,8 @@ if ((re->options & PCRE_ANCHORED) == 0) re->flags |= PCRE_FIRSTSET; } - else if (is_startline(codestart, 0, cd->backref_map)) - re->flags |= PCRE_STARTLINE; + + else if (is_startline(codestart, 0, cd, 0)) re->flags |= PCRE_STARTLINE; } } @@ -8120,17 +9325,17 @@ if ((re->options & PCRE_ANCHORED) == 0) variable length item in the regex. Remove the caseless flag for non-caseable bytes. */ -if (reqchar >= 0 && - ((re->options & PCRE_ANCHORED) == 0 || (reqchar & REQ_VARY) != 0)) +if (reqcharflags >= 0 && + ((re->options & PCRE_ANCHORED) == 0 || (reqcharflags & REQ_VARY) != 0)) { -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 re->req_char = reqchar & 0xff; -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 re->req_char = reqchar & 0xffff; +#elif defined COMPILE_PCRE32 + re->req_char = reqchar; #endif -#endif - if ((reqchar & REQ_CASELESS) != 0) + if ((reqcharflags & REQ_CASELESS) != 0) { #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8) /* We ignore non-ASCII first chars in 8 bit mode. */ @@ -8180,10 +9385,12 @@ if ((re->flags & PCRE_REQCHSET) != 0) else printf("Req char = \\x%02x%s\n", ch, caseless); } -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 pcre_printint((pcre *)re, stdout, TRUE); -#else +#elif defined COMPILE_PCRE16 pcre16_printint((pcre *)re, stdout, TRUE); +#elif defined COMPILE_PCRE32 +pcre32_printint((pcre *)re, stdout, TRUE); #endif /* This check is done here in the debugging case so that the code that @@ -8199,11 +9406,28 @@ if (code - codestart > length) } #endif /* PCRE_DEBUG */ -#ifdef COMPILE_PCRE8 +/* Check for a pattern than can match an empty string, so that this information +can be provided to applications. */ + +do + { + if (could_be_empty_branch(codestart, code, utf, cd, NULL)) + { + re->flags |= PCRE_MATCH_EMPTY; + break; + } + codestart += GET(codestart, 1); + } +while (*codestart == OP_ALT); + +#if defined COMPILE_PCRE8 return (pcre *)re; -#else +#elif defined COMPILE_PCRE16 return (pcre16 *)re; +#elif defined COMPILE_PCRE32 +return (pcre32 *)re; #endif } /* End of pcre_compile.c */ + diff --git a/src/3rd/pcre/pcreconf.c b/src/3rd/pcre/pcreconf.c index 8d4a7f078e..9cb4515983 100644 --- a/src/3rd/pcre/pcreconf.c +++ b/src/3rd/pcre/pcreconf.c @@ -65,18 +65,21 @@ Arguments: Returns: 0 if data returned, negative on error */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_config(int what, void *where) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_config(int what, void *where) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_config(int what, void *where) #endif { switch (what) { case PCRE_CONFIG_UTF8: -#if defined COMPILE_PCRE16 +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 *((int *)where) = 0; return PCRE_ERROR_BADOPTION; #else @@ -89,7 +92,20 @@ switch (what) #endif case PCRE_CONFIG_UTF16: -#if defined COMPILE_PCRE8 +#if defined COMPILE_PCRE8 || defined COMPILE_PCRE32 + *((int *)where) = 0; + return PCRE_ERROR_BADOPTION; +#else +#if defined SUPPORT_UTF + *((int *)where) = 1; +#else + *((int *)where) = 0; +#endif + break; +#endif + + case PCRE_CONFIG_UTF32: +#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 *((int *)where) = 0; return PCRE_ERROR_BADOPTION; #else @@ -145,6 +161,10 @@ switch (what) *((int *)where) = POSIX_MALLOC_THRESHOLD; break; + case PCRE_CONFIG_PARENS_LIMIT: + *((unsigned long int *)where) = PARENS_NEST_LIMIT; + break; + case PCRE_CONFIG_MATCH_LIMIT: *((unsigned long int *)where) = MATCH_LIMIT; break; diff --git a/src/3rd/pcre/pcredfa.c b/src/3rd/pcre/pcredfa.c index 509e1ce6c3..aa02ef39fd 100644 --- a/src/3rd/pcre/pcredfa.c +++ b/src/3rd/pcre/pcredfa.c @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language (but see below for why this module is different). Written by Philip Hazel - Copyright (c) 1997-2012 University of Cambridge + Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -120,7 +120,7 @@ static const pcre_uint8 coptable[] = { 0, 0, /* \P, \p */ 0, 0, 0, 0, 0, /* \R, \H, \h, \V, \v */ 0, /* \X */ - 0, 0, 0, 0, 0, 0, /* \Z, \z, ^, ^M, $, $M */ + 0, 0, 0, 0, 0, 0, /* \Z, \z, $, $M, ^, ^M */ 1, /* Char */ 1, /* Chari */ 1, /* not */ @@ -151,11 +151,14 @@ static const pcre_uint8 coptable[] = { /* Character class & ref repeats */ 0, 0, 0, 0, 0, 0, /* *, *?, +, +?, ?, ?? */ 0, 0, /* CRRANGE, CRMINRANGE */ + 0, 0, 0, 0, /* Possessive *+, ++, ?+, CRPOSRANGE */ 0, /* CLASS */ 0, /* NCLASS */ 0, /* XCLASS - variable length */ 0, /* REF */ 0, /* REFI */ + 0, /* DNREF */ + 0, /* DNREFI */ 0, /* RECURSE */ 0, /* CALLOUT */ 0, /* Alt */ @@ -171,8 +174,8 @@ static const pcre_uint8 coptable[] = { 0, 0, /* ONCE, ONCE_NC */ 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */ 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */ - 0, 0, /* CREF, NCREF */ - 0, 0, /* RREF, NRREF */ + 0, 0, /* CREF, DNCREF */ + 0, 0, /* RREF, DNRREF */ 0, /* DEF */ 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */ @@ -194,7 +197,7 @@ static const pcre_uint8 poptable[] = { 1, 1, /* \P, \p */ 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ 1, /* \X */ - 0, 0, 0, 0, 0, 0, /* \Z, \z, ^, ^M, $, $M */ + 0, 0, 0, 0, 0, 0, /* \Z, \z, $, $M, ^, ^M */ 1, /* Char */ 1, /* Chari */ 1, /* not */ @@ -220,11 +223,14 @@ static const pcre_uint8 poptable[] = { /* Character class & ref repeats */ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ 1, 1, /* CRRANGE, CRMINRANGE */ + 1, 1, 1, 1, /* Possessive *+, ++, ?+, CRPOSRANGE */ 1, /* CLASS */ 1, /* NCLASS */ 1, /* XCLASS - variable length */ 0, /* REF */ 0, /* REFI */ + 0, /* DNREF */ + 0, /* DNREFI */ 0, /* RECURSE */ 0, /* CALLOUT */ 0, /* Alt */ @@ -240,8 +246,8 @@ static const pcre_uint8 poptable[] = { 0, 0, /* ONCE, ONCE_NC */ 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */ 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */ - 0, 0, /* CREF, NCREF */ - 0, 0, /* RREF, NRREF */ + 0, 0, /* CREF, DNCREF */ + 0, 0, /* RREF, DNRREF */ 0, /* DEF */ 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */ @@ -302,13 +308,13 @@ Returns: nothing static void pchars(const pcre_uchar *p, int length, FILE *f) { -int c; +pcre_uint32 c; while (length-- > 0) { if (isprint(c = *(p++))) fprintf(f, "%c", c); else - fprintf(f, "\\x%02x", c); + fprintf(f, "\\x{%02x}", c); } } #endif @@ -571,7 +577,7 @@ for (;;) { int i, j; int clen, dlen; - unsigned int c, d; + pcre_uint32 c, d; int forced_fail = 0; BOOL partial_newline = FALSE; BOOL could_continue = reset_could_continue; @@ -613,9 +619,10 @@ for (;;) { clen = 1; /* Number of data items in the character */ #ifdef SUPPORT_UTF - if (utf) { GETCHARLEN(c, ptr, clen); } else -#endif /* SUPPORT_UTF */ + GETCHARLENTEST(c, ptr, clen); +#else c = *ptr; +#endif /* SUPPORT_UTF */ } else { @@ -634,7 +641,8 @@ for (;;) BOOL caseless = FALSE; const pcre_uchar *code; int state_offset = current_state->offset; - int count, codevalue, rrc; + int codevalue, rrc; + int count; #ifdef PCRE_DEBUG printf ("%.*sProcessing state %d c=", rlevel*2-2, SP, state_offset); @@ -1007,7 +1015,7 @@ for (;;) { const pcre_uchar *temp = ptr - 1; if (temp < md->start_used_ptr) md->start_used_ptr = temp; -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) { BACKCHAR(temp); } #endif GETCHARTEST(d, temp); @@ -1060,6 +1068,7 @@ for (;;) if (clen > 0) { BOOL OK; + const pcre_uint32 *cp; const ucd_record * prop = GET_UCD(c); switch(code[1]) { @@ -1091,15 +1100,23 @@ for (;;) PRIV(ucp_gentype)[prop->chartype] == ucp_N; break; - case PT_SPACE: /* Perl space */ - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR; - break; + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ + case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_VT || - c == CHAR_FF || c == CHAR_CR; + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + OK = TRUE; + break; + + default: + OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; + break; + } break; case PT_WORD: @@ -1108,6 +1125,21 @@ for (;;) c == CHAR_UNDERSCORE; break; + case PT_CLIST: + cp = PRIV(ucd_caseless_sets) + code[2]; + for (;;) + { + if (c < *cp) { OK = FALSE; break; } + if (c == *cp++) { OK = TRUE; break; } + } + break; + + case PT_UCNC: + OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || + c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || + c >= 0xe000; + break; + /* Should never occur, but keep compilers from grumbling. */ default: @@ -1237,7 +1269,7 @@ for (;;) (d != OP_ANY || !IS_NEWLINE(ptr)) && ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) { - if (++count >= GET2(code, 1)) + if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + 1 + IMM2_SIZE + 1, 0); } else { ADD_NEW(state_offset, count); } @@ -1271,7 +1303,7 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } - if (++count >= GET2(code, 1)) + if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + 2 + IMM2_SIZE, 0); } else { ADD_NEW(state_offset, count); } @@ -1294,6 +1326,7 @@ for (;;) if (clen > 0) { BOOL OK; + const pcre_uint32 *cp; const ucd_record * prop = GET_UCD(c); switch(code[2]) { @@ -1325,15 +1358,23 @@ for (;;) PRIV(ucp_gentype)[prop->chartype] == ucp_N; break; - case PT_SPACE: /* Perl space */ - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR; - break; + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ + case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_VT || - c == CHAR_FF || c == CHAR_CR; + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + OK = TRUE; + break; + + default: + OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; + break; + } break; case PT_WORD: @@ -1342,6 +1383,21 @@ for (;;) c == CHAR_UNDERSCORE; break; + case PT_CLIST: + cp = PRIV(ucd_caseless_sets) + code[3]; + for (;;) + { + if (c < *cp) { OK = FALSE; break; } + if (c == *cp++) { OK = TRUE; break; } + } + break; + + case PT_UCNC: + OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || + c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || + c >= 0xe000; + break; + /* Should never occur, but keep compilers from grumbling. */ default: @@ -1368,8 +1424,9 @@ for (;;) case OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } - if (clen > 0 && UCD_CATEGORY(c) != ucp_M) + if (clen > 0) { + int lgb, rgb; const pcre_uchar *nptr = ptr + clen; int ncount = 0; if (count > 0 && codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS) @@ -1377,14 +1434,16 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } + lgb = UCD_GRAPHBREAK(c); while (nptr < end_subject) { - int nd; - int ndlen = 1; - GETCHARLEN(nd, nptr, ndlen); - if (UCD_CATEGORY(nd) != ucp_M) break; + dlen = 1; + if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } + rgb = UCD_GRAPHBREAK(d); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; ncount++; - nptr += ndlen; + lgb = rgb; + nptr += dlen; } count++; ADD_NEW_DATA(-state_offset, count, ncount); @@ -1403,20 +1462,22 @@ for (;;) int ncount = 0; switch (c) { - case 0x000b: - case 0x000c: - case 0x0085: + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC case 0x2028: case 0x2029: +#endif /* Not EBCDIC */ if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; goto ANYNL01; - case 0x000d: - if (ptr + 1 < end_subject && ptr[1] == 0x0a) ncount = 1; + case CHAR_CR: + if (ptr + 1 < end_subject && RAWUCHARTEST(ptr + 1) == CHAR_LF) ncount = 1; /* Fall through */ ANYNL01: - case 0x000a: + case CHAR_LF: if (count > 0 && codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSPLUS) { active_count--; /* Remove non-match possibility */ @@ -1443,13 +1504,7 @@ for (;;) BOOL OK; switch (c) { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: + VSPACE_CASES: OK = TRUE; break; @@ -1482,25 +1537,7 @@ for (;;) BOOL OK; switch (c) { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ + HSPACE_CASES: OK = TRUE; break; @@ -1541,6 +1578,7 @@ for (;;) if (clen > 0) { BOOL OK; + const pcre_uint32 *cp; const ucd_record * prop = GET_UCD(c); switch(code[2]) { @@ -1572,15 +1610,23 @@ for (;;) PRIV(ucp_gentype)[prop->chartype] == ucp_N; break; - case PT_SPACE: /* Perl space */ - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR; - break; + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ + case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_VT || - c == CHAR_FF || c == CHAR_CR; + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + OK = TRUE; + break; + + default: + OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; + break; + } break; case PT_WORD: @@ -1589,6 +1635,21 @@ for (;;) c == CHAR_UNDERSCORE; break; + case PT_CLIST: + cp = PRIV(ucd_caseless_sets) + code[3]; + for (;;) + { + if (c < *cp) { OK = FALSE; break; } + if (c == *cp++) { OK = TRUE; break; } + } + break; + + case PT_UCNC: + OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || + c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || + c >= 0xe000; + break; + /* Should never occur, but keep compilers from grumbling. */ default: @@ -1624,8 +1685,9 @@ for (;;) QS2: ADD_ACTIVE(state_offset + 2, 0); - if (clen > 0 && UCD_CATEGORY(c) != ucp_M) + if (clen > 0) { + int lgb, rgb; const pcre_uchar *nptr = ptr + clen; int ncount = 0; if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR || @@ -1634,14 +1696,16 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } + lgb = UCD_GRAPHBREAK(c); while (nptr < end_subject) { - int nd; - int ndlen = 1; - GETCHARLEN(nd, nptr, ndlen); - if (UCD_CATEGORY(nd) != ucp_M) break; + dlen = 1; + if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } + rgb = UCD_GRAPHBREAK(d); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; ncount++; - nptr += ndlen; + lgb = rgb; + nptr += dlen; } ADD_NEW_DATA(-(state_offset + count), 0, ncount); } @@ -1667,27 +1731,29 @@ for (;;) int ncount = 0; switch (c) { - case 0x000b: - case 0x000c: - case 0x0085: + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC case 0x2028: case 0x2029: +#endif /* Not EBCDIC */ if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; goto ANYNL02; - case 0x000d: - if (ptr + 1 < end_subject && ptr[1] == 0x0a) ncount = 1; + case CHAR_CR: + if (ptr + 1 < end_subject && RAWUCHARTEST(ptr + 1) == CHAR_LF) ncount = 1; /* Fall through */ ANYNL02: - case 0x000a: + case CHAR_LF: if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSSTAR || codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSQUERY) { active_count--; /* Remove non-match possibility */ next_active_state--; } - ADD_NEW_DATA(-(state_offset + count), 0, ncount); + ADD_NEW_DATA(-(state_offset + (int)count), 0, ncount); break; default: @@ -1715,13 +1781,7 @@ for (;;) BOOL OK; switch (c) { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: + VSPACE_CASES: OK = TRUE; break; @@ -1737,7 +1797,7 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } - ADD_NEW_DATA(-(state_offset + count), 0, 0); + ADD_NEW_DATA(-(state_offset + (int)count), 0, 0); } } break; @@ -1761,25 +1821,7 @@ for (;;) BOOL OK; switch (c) { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ + HSPACE_CASES: OK = TRUE; break; @@ -1796,7 +1838,7 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } - ADD_NEW_DATA(-(state_offset + count), 0, 0); + ADD_NEW_DATA(-(state_offset + (int)count), 0, 0); } } break; @@ -1813,6 +1855,7 @@ for (;;) if (clen > 0) { BOOL OK; + const pcre_uint32 *cp; const ucd_record * prop = GET_UCD(c); switch(code[1 + IMM2_SIZE + 1]) { @@ -1844,15 +1887,23 @@ for (;;) PRIV(ucp_gentype)[prop->chartype] == ucp_N; break; - case PT_SPACE: /* Perl space */ - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR; - break; + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ + case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ - OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_VT || - c == CHAR_FF || c == CHAR_CR; + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + OK = TRUE; + break; + + default: + OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; + break; + } break; case PT_WORD: @@ -1861,6 +1912,21 @@ for (;;) c == CHAR_UNDERSCORE; break; + case PT_CLIST: + cp = PRIV(ucd_caseless_sets) + code[1 + IMM2_SIZE + 2]; + for (;;) + { + if (c < *cp) { OK = FALSE; break; } + if (c == *cp++) { OK = TRUE; break; } + } + break; + + case PT_UCNC: + OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || + c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || + c >= 0xe000; + break; + /* Should never occur, but keep compilers from grumbling. */ default: @@ -1875,7 +1941,7 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } - if (++count >= GET2(code, 1)) + if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + 1 + IMM2_SIZE + 3, 0); } else { ADD_NEW(state_offset, count); } @@ -1891,8 +1957,9 @@ for (;;) if (codevalue != OP_EXTUNI_EXTRA + OP_TYPEEXACT) { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); } count = current_state->count; /* Number already matched */ - if (clen > 0 && UCD_CATEGORY(c) != ucp_M) + if (clen > 0) { + int lgb, rgb; const pcre_uchar *nptr = ptr + clen; int ncount = 0; if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO) @@ -1900,18 +1967,20 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } + lgb = UCD_GRAPHBREAK(c); while (nptr < end_subject) { - int nd; - int ndlen = 1; - GETCHARLEN(nd, nptr, ndlen); - if (UCD_CATEGORY(nd) != ucp_M) break; + dlen = 1; + if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } + rgb = UCD_GRAPHBREAK(d); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; ncount++; - nptr += ndlen; + lgb = rgb; + nptr += dlen; } if (nptr >= end_subject && (md->moptions & PCRE_PARTIAL_HARD) != 0) reset_could_continue = TRUE; - if (++count >= GET2(code, 1)) + if (++count >= (int)GET2(code, 1)) { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); } else { ADD_NEW_DATA(-state_offset, count, ncount); } @@ -1932,26 +2001,28 @@ for (;;) int ncount = 0; switch (c) { - case 0x000b: - case 0x000c: - case 0x0085: + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC case 0x2028: case 0x2029: +#endif /* Not EBCDIC */ if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; goto ANYNL03; - case 0x000d: - if (ptr + 1 < end_subject && ptr[1] == 0x0a) ncount = 1; + case CHAR_CR: + if (ptr + 1 < end_subject && RAWUCHARTEST(ptr + 1) == CHAR_LF) ncount = 1; /* Fall through */ ANYNL03: - case 0x000a: + case CHAR_LF: if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSUPTO) { active_count--; /* Remove non-match possibility */ next_active_state--; } - if (++count >= GET2(code, 1)) + if (++count >= (int)GET2(code, 1)) { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); } else { ADD_NEW_DATA(-state_offset, count, ncount); } @@ -1976,13 +2047,7 @@ for (;;) BOOL OK; switch (c) { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: + VSPACE_CASES: OK = TRUE; break; @@ -1997,7 +2062,7 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } - if (++count >= GET2(code, 1)) + if (++count >= (int)GET2(code, 1)) { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); } else { ADD_NEW_DATA(-state_offset, count, 0); } @@ -2018,25 +2083,7 @@ for (;;) BOOL OK; switch (c) { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ + HSPACE_CASES: OK = TRUE; break; @@ -2052,7 +2099,7 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } - if (++count >= GET2(code, 1)) + if (++count >= (int)GET2(code, 1)) { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); } else { ADD_NEW_DATA(-state_offset, count, 0); } @@ -2112,17 +2159,21 @@ for (;;) to wait for them to pass before continuing. */ case OP_EXTUNI: - if (clen > 0 && UCD_CATEGORY(c) != ucp_M) + if (clen > 0) { + int lgb, rgb; const pcre_uchar *nptr = ptr + clen; int ncount = 0; + lgb = UCD_GRAPHBREAK(c); while (nptr < end_subject) { - int nclen = 1; - GETCHARLEN(c, nptr, nclen); - if (UCD_CATEGORY(c) != ucp_M) break; + dlen = 1; + if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } + rgb = UCD_GRAPHBREAK(d); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; ncount++; - nptr += nclen; + lgb = rgb; + nptr += dlen; } if (nptr >= end_subject && (md->moptions & PCRE_PARTIAL_HARD) != 0) reset_could_continue = TRUE; @@ -2139,25 +2190,27 @@ for (;;) case OP_ANYNL: if (clen > 0) switch(c) { - case 0x000b: - case 0x000c: - case 0x0085: + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC case 0x2028: case 0x2029: +#endif /* Not EBCDIC */ if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; - case 0x000a: + case CHAR_LF: ADD_NEW(state_offset + 1, 0); break; - case 0x000d: + case CHAR_CR: if (ptr + 1 >= end_subject) { ADD_NEW(state_offset + 1, 0); if ((md->moptions & PCRE_PARTIAL_HARD) != 0) reset_could_continue = TRUE; } - else if (ptr[1] == 0x0a) + else if (RAWUCHARTEST(ptr + 1) == CHAR_LF) { ADD_NEW_DATA(-(state_offset + 1), 0, 1); } @@ -2173,13 +2226,7 @@ for (;;) case OP_NOT_VSPACE: if (clen > 0) switch(c) { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: + VSPACE_CASES: break; default: @@ -2192,17 +2239,12 @@ for (;;) case OP_VSPACE: if (clen > 0) switch(c) { - case 0x000a: - case 0x000b: - case 0x000c: - case 0x000d: - case 0x0085: - case 0x2028: - case 0x2029: + VSPACE_CASES: ADD_NEW(state_offset + 1, 0); break; - default: break; + default: + break; } break; @@ -2210,25 +2252,7 @@ for (;;) case OP_NOT_HSPACE: if (clen > 0) switch(c) { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ + HSPACE_CASES: break; default: @@ -2241,27 +2265,12 @@ for (;;) case OP_HSPACE: if (clen > 0) switch(c) { - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ + HSPACE_CASES: ADD_NEW(state_offset + 1, 0); break; + + default: + break; } break; @@ -2315,7 +2324,7 @@ for (;;) if (count > 0) { ADD_ACTIVE(state_offset + dlen + 1, 0); } if (clen > 0) { - unsigned int otherd = NOTACHAR; + pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF @@ -2362,7 +2371,7 @@ for (;;) ADD_ACTIVE(state_offset + dlen + 1, 0); if (clen > 0) { - unsigned int otherd = NOTACHAR; + pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF @@ -2407,7 +2416,7 @@ for (;;) ADD_ACTIVE(state_offset + dlen + 1, 0); if (clen > 0) { - unsigned int otherd = NOTACHAR; + pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF @@ -2444,7 +2453,7 @@ for (;;) count = current_state->count; /* Number already matched */ if (clen > 0) { - unsigned int otherd = NOTACHAR; + pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF @@ -2460,7 +2469,7 @@ for (;;) } if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) { - if (++count >= GET2(code, 1)) + if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); } else { ADD_NEW(state_offset, count); } @@ -2488,7 +2497,7 @@ for (;;) count = current_state->count; /* Number already matched */ if (clen > 0) { - unsigned int otherd = NOTACHAR; + pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF @@ -2509,7 +2518,7 @@ for (;;) active_count--; /* Remove non-match possibility */ next_active_state--; } - if (++count >= GET2(code, 1)) + if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); } else { ADD_NEW(state_offset, count); } @@ -2562,31 +2571,65 @@ for (;;) { case OP_CRSTAR: case OP_CRMINSTAR: + case OP_CRPOSSTAR: ADD_ACTIVE(next_state_offset + 1, 0); - if (isinclass) { ADD_NEW(state_offset, 0); } + if (isinclass) + { + if (*ecode == OP_CRPOSSTAR) + { + active_count--; /* Remove non-match possibility */ + next_active_state--; + } + ADD_NEW(state_offset, 0); + } break; case OP_CRPLUS: case OP_CRMINPLUS: + case OP_CRPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(next_state_offset + 1, 0); } - if (isinclass) { count++; ADD_NEW(state_offset, count); } + if (isinclass) + { + if (count > 0 && *ecode == OP_CRPOSPLUS) + { + active_count--; /* Remove non-match possibility */ + next_active_state--; + } + count++; + ADD_NEW(state_offset, count); + } break; case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRPOSQUERY: ADD_ACTIVE(next_state_offset + 1, 0); - if (isinclass) { ADD_NEW(next_state_offset + 1, 0); } + if (isinclass) + { + if (*ecode == OP_CRPOSQUERY) + { + active_count--; /* Remove non-match possibility */ + next_active_state--; + } + ADD_NEW(next_state_offset + 1, 0); + } break; case OP_CRRANGE: case OP_CRMINRANGE: + case OP_CRPOSRANGE: count = current_state->count; /* Already matched */ - if (count >= GET2(ecode, 1)) + if (count >= (int)GET2(ecode, 1)) { ADD_ACTIVE(next_state_offset + 1 + 2 * IMM2_SIZE, 0); } if (isinclass) { - int max = GET2(ecode, 1 + IMM2_SIZE); + int max = (int)GET2(ecode, 1 + IMM2_SIZE); + if (*ecode == OP_CRPOSRANGE) + { + active_count--; /* Remove non-match possibility */ + next_active_state--; + } if (++count >= max && max != 0) /* Max 0 => no limit */ { ADD_NEW(next_state_offset + 1 + 2 * IMM2_SIZE, 0); } else @@ -2662,10 +2705,12 @@ for (;;) cb.version = 1; /* Version 1 of the callout block */ cb.callout_number = code[LINK_SIZE+2]; cb.offset_vector = offsets; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 cb.subject = (PCRE_SPTR)start_subject; -#else +#elif defined COMPILE_PCRE16 cb.subject = (PCRE_SPTR16)start_subject; +#elif defined COMPILE_PCRE32 + cb.subject = (PCRE_SPTR32)start_subject; #endif cb.subject_length = (int)(end_subject - start_subject); cb.start_match = (int)(current_subject - start_subject); @@ -2684,9 +2729,11 @@ for (;;) condcode = code[LINK_SIZE+1]; - /* Back reference conditions are not supported */ + /* Back reference conditions and duplicate named recursion conditions + are not supported */ - if (condcode == OP_CREF || condcode == OP_NCREF) + if (condcode == OP_CREF || condcode == OP_DNCREF || + condcode == OP_DNRREF) return PCRE_ERROR_DFA_UCOND; /* The DEFINE condition is always false */ @@ -2698,7 +2745,7 @@ for (;;) which means "test if in any recursion". We can't test for specifically recursed groups. */ - else if (condcode == OP_RREF || condcode == OP_NRREF) + else if (condcode == OP_RREF) { int value = GET2(code, LINK_SIZE + 2); if (value != RREF_ANY) return PCRE_ERROR_DFA_UCOND; @@ -2796,7 +2843,7 @@ for (;;) for (rc = rc*2 - 2; rc >= 0; rc -= 2) { int charcount = local_offsets[rc+1] - local_offsets[rc]; -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) { const pcre_uchar *p = start_subject + local_offsets[rc]; @@ -2900,7 +2947,7 @@ for (;;) const pcre_uchar *p = ptr; const pcre_uchar *pp = local_ptr; charcount = (int)(pp - p); -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) while (p < pp) if (NOT_FIRSTCHAR(*p++)) charcount--; #endif ADD_NEW_DATA(-next_state_offset, 0, (charcount - 1)); @@ -2982,7 +3029,7 @@ for (;;) } else { -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) { const pcre_uchar *p = start_subject + local_offsets[0]; @@ -3011,10 +3058,12 @@ for (;;) cb.version = 1; /* Version 1 of the callout block */ cb.callout_number = code[1]; cb.offset_vector = offsets; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 cb.subject = (PCRE_SPTR)start_subject; -#else +#elif defined COMPILE_PCRE16 cb.subject = (PCRE_SPTR16)start_subject; +#elif defined COMPILE_PCRE32 + cb.subject = (PCRE_SPTR32)start_subject; #endif cb.subject_length = (int)(end_subject - start_subject); cb.start_match = (int)(current_subject - start_subject); @@ -3072,15 +3121,7 @@ for (;;) ptr > md->start_used_ptr) /* Inspected non-empty string */ ) ) - { - if (offsetcount >= 2) - { - offsets[0] = (int)(md->start_used_ptr - start_subject); - offsets[1] = (int)(end_subject - start_subject); - } match_count = PCRE_ERROR_PARTIAL; - } - DPRINTF(("%.*sEnd of internal_dfa_exec %d: returning %d\n" "%.*s---------------------\n\n", rlevel*2-2, SP, rlevel, match_count, rlevel*2-2, SP)); @@ -3130,16 +3171,21 @@ Returns: > 0 => number of match offset pairs placed in offsets < -1 => some kind of unexpected problem */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_dfa_exec(const pcre *argument_re, const pcre_extra *extra_data, const char *subject, int length, int start_offset, int options, int *offsets, int offsetcount, int *workspace, int wscount) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_dfa_exec(const pcre16 *argument_re, const pcre16_extra *extra_data, PCRE_SPTR16 subject, int length, int start_offset, int options, int *offsets, int offsetcount, int *workspace, int wscount) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_dfa_exec(const pcre32 *argument_re, const pcre32_extra *extra_data, + PCRE_SPTR32 subject, int length, int start_offset, int options, int *offsets, + int offsetcount, int *workspace, int wscount) #endif { REAL_PCRE *re = (REAL_PCRE *)argument_re; @@ -3166,6 +3212,7 @@ if (re == NULL || subject == NULL || workspace == NULL || (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; if (offsetcount < 0) return PCRE_ERROR_BADCOUNT; if (wscount < 20) return PCRE_ERROR_DFA_WSSIZE; +if (length < 0) return PCRE_ERROR_BADLENGTH; if (start_offset < 0 || start_offset > length) return PCRE_ERROR_BADOFFSET; /* Check that the first field in the block is the magic number. If it is not, @@ -3214,7 +3261,7 @@ end_subject = (const pcre_uchar *)subject + length; req_char_ptr = current_subject - 1; #ifdef SUPPORT_UTF -/* PCRE_UTF16 has the same value as PCRE_UTF8. */ +/* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */ utf = (re->options & PCRE_UTF8) != 0; #else utf = FALSE; @@ -3300,12 +3347,21 @@ if (utf && (options & PCRE_NO_UTF8_CHECK) == 0) offsets[0] = erroroffset; offsets[1] = errorcode; } - return (errorcode <= PCRE_UTF8_ERR5 && (options & PCRE_PARTIAL_HARD) != 0)? +#if defined COMPILE_PCRE8 + return (errorcode <= PCRE_UTF8_ERR5 && (options & PCRE_PARTIAL_HARD) != 0) ? PCRE_ERROR_SHORTUTF8 : PCRE_ERROR_BADUTF8; +#elif defined COMPILE_PCRE16 + return (errorcode <= PCRE_UTF16_ERR1 && (options & PCRE_PARTIAL_HARD) != 0) ? + PCRE_ERROR_SHORTUTF16 : PCRE_ERROR_BADUTF16; +#elif defined COMPILE_PCRE32 + return PCRE_ERROR_BADUTF32; +#endif } +#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 if (start_offset > 0 && start_offset < length && NOT_FIRSTCHAR(((PCRE_PUCHAR)subject)[start_offset])) return PCRE_ERROR_BADUTF8_OFFSET; +#endif } #endif @@ -3415,12 +3471,15 @@ for (;;) if (has_first_char) { if (first_char != first_char2) + { + pcre_uchar csc; while (current_subject < end_subject && - *current_subject != first_char && *current_subject != first_char2) + (csc = RAWUCHARTEST(current_subject)) != first_char && csc != first_char2) current_subject++; + } else while (current_subject < end_subject && - *current_subject != first_char) + RAWUCHARTEST(current_subject) != first_char) current_subject++; } @@ -3450,10 +3509,10 @@ for (;;) ANYCRLF, and we are now at a LF, advance the match position by one more character. */ - if (current_subject[-1] == CHAR_CR && + if (RAWUCHARTEST(current_subject - 1) == CHAR_CR && (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) && current_subject < end_subject && - *current_subject == CHAR_NL) + RAWUCHARTEST(current_subject) == CHAR_NL) current_subject++; } } @@ -3464,7 +3523,7 @@ for (;;) { while (current_subject < end_subject) { - register unsigned int c = *current_subject; + register pcre_uint32 c = RAWUCHARTEST(current_subject); #ifndef COMPILE_PCRE8 if (c > 255) c = 255; #endif @@ -3530,7 +3589,7 @@ for (;;) { while (p < end_subject) { - register int pp = *p++; + register pcre_uint32 pp = RAWUCHARINCTEST(p); if (pp == req_char || pp == req_char2) { p--; break; } } } @@ -3538,7 +3597,7 @@ for (;;) { while (p < end_subject) { - if (*p++ == req_char) { p--; break; } + if (RAWUCHARINCTEST(p) == req_char) { p--; break; } } } @@ -3576,7 +3635,17 @@ for (;;) /* Anything other than "no match" means we are done, always; otherwise, carry on only if not anchored. */ - if (rc != PCRE_ERROR_NOMATCH || anchored) return rc; + if (rc != PCRE_ERROR_NOMATCH || anchored) + { + if (rc == PCRE_ERROR_PARTIAL && offsetcount >= 2) + { + offsets[0] = (int)(md->start_used_ptr - (PCRE_PUCHAR)subject); + offsets[1] = (int)(end_subject - (PCRE_PUCHAR)subject); + if (offsetcount > 2) + offsets[2] = (int)(current_subject - (PCRE_PUCHAR)subject); + } + return rc; + } /* Advance to the next subject character unless we are at the end of a line and firstline is set. */ @@ -3596,9 +3665,9 @@ for (;;) not contain any explicit matches for \r or \n, and the newline option is CRLF or ANY or ANYCRLF, advance the match position by one more character. */ - if (current_subject[-1] == CHAR_CR && + if (RAWUCHARTEST(current_subject - 1) == CHAR_CR && current_subject < end_subject && - *current_subject == CHAR_NL && + RAWUCHARTEST(current_subject) == CHAR_NL && (re->flags & PCRE_HASCRORLF) == 0 && (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF || diff --git a/src/3rd/pcre/pcreexec.c b/src/3rd/pcre/pcreexec.c index 67c8afefa3..234fadaf91 100644 --- a/src/3rd/pcre/pcreexec.c +++ b/src/3rd/pcre/pcreexec.c @@ -6,7 +6,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2012 University of Cambridge + Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -56,6 +56,20 @@ possible. There are also some static supporting functions. */ #undef min #undef max +/* The md->capture_last field uses the lower 16 bits for the last captured +substring (which can never be greater than 65535) and a bit in the top half +to mean "capture vector overflowed". This odd way of doing things was +implemented when it was realized that preserving and restoring the overflow bit +whenever the last capture number was saved/restored made for a neater +interface, and doing it this way saved on (a) another variable, which would +have increased the stack frame size (a big NO-NO in PCRE) and (b) another +separate set of save/restore instructions. The following defines are used in +implementing this. */ + +#define CAPLMASK 0x0000ffff /* The bits used for last_capture */ +#define OVFLMASK 0xffff0000 /* The bits used for the overflow flag */ +#define OVFLBIT 0x00010000 /* The bit that is set for overflow */ + /* Values for setting in md->match_function_type to indicate two special types of call to match(). We do it this way to save on using another stack variable, as stack usage is to be discouraged. */ @@ -73,13 +87,17 @@ defined PCRE_ERROR_xxx codes, which are all negative. */ negative to avoid the external error codes. */ #define MATCH_ACCEPT (-999) -#define MATCH_COMMIT (-998) -#define MATCH_KETRPOS (-997) -#define MATCH_ONCE (-996) +#define MATCH_KETRPOS (-998) +#define MATCH_ONCE (-997) +/* The next 5 must be kept together and in sequence so that a test that checks +for any one of them can use a range. */ +#define MATCH_COMMIT (-996) #define MATCH_PRUNE (-995) #define MATCH_SKIP (-994) #define MATCH_SKIP_ARG (-993) #define MATCH_THEN (-992) +#define MATCH_BACKTRACK_MAX MATCH_THEN +#define MATCH_BACKTRACK_MIN MATCH_COMMIT /* Maximum number of ints of offset to save on the stack for recursive calls. If the offset vector is bigger, malloc is used. This should be a multiple of 3, @@ -89,10 +107,8 @@ because the offset vector is always a multiple of 3 long. */ /* Min and max values for the common repeats; for the maxima, 0 => infinity */ -static const char rep_min[] = { 0, 0, 1, 1, 0, 0 }; -static const char rep_max[] = { 0, 0, 0, 0, 1, 1 }; - - +static const char rep_min[] = { 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, }; +static const char rep_max[] = { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, }; #ifdef PCRE_DEBUG /************************************************* @@ -114,10 +130,11 @@ Returns: nothing static void pchars(const pcre_uchar *p, int length, BOOL is_subject, match_data *md) { -unsigned int c; +pcre_uint32 c; +BOOL utf = md->utf; if (is_subject && length > md->end_subject - p) length = md->end_subject - p; while (length-- > 0) - if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c); + if (isprint(c = RAWUCHARINCTEST(p))) printf("%c", (char)c); else printf("\\x{%02x}", c); } #endif @@ -150,6 +167,9 @@ match_ref(int offset, register PCRE_PUCHAR eptr, int length, match_data *md, { PCRE_PUCHAR eptr_start = eptr; register PCRE_PUCHAR p = md->start_subject + md->offset_vector[offset]; +#if defined SUPPORT_UTF && defined SUPPORT_UCP +BOOL utf = md->utf; +#endif #ifdef PCRE_DEBUG if (eptr >= md->end_subject) @@ -175,30 +195,39 @@ ASCII characters. */ if (caseless) { -#ifdef SUPPORT_UTF -#ifdef SUPPORT_UCP - if (md->utf) +#if defined SUPPORT_UTF && defined SUPPORT_UCP + if (utf) { /* Match characters up to the end of the reference. NOTE: the number of - bytes matched may differ, because there are some characters whose upper and - lower case versions code as different numbers of bytes. For example, U+023A - (2 bytes in UTF-8) is the upper case version of U+2C65 (3 bytes in UTF-8); - a sequence of 3 of the former uses 6 bytes, as does a sequence of two of - the latter. It is important, therefore, to check the length along the - reference, not along the subject (earlier code did this wrong). */ + data units matched may differ, because in UTF-8 there are some characters + whose upper and lower case versions code have different numbers of bytes. + For example, U+023A (2 bytes in UTF-8) is the upper case version of U+2C65 + (3 bytes in UTF-8); a sequence of 3 of the former uses 6 bytes, as does a + sequence of two of the latter. It is important, therefore, to check the + length along the reference, not along the subject (earlier code did this + wrong). */ PCRE_PUCHAR endptr = p + length; while (p < endptr) { - int c, d; + pcre_uint32 c, d; + const ucd_record *ur; if (eptr >= md->end_subject) return -2; /* Partial match */ GETCHARINC(c, eptr); GETCHARINC(d, p); - if (c != d && c != UCD_OTHERCASE(d)) return -1; + ur = GET_UCD(d); + if (c != d && c != d + ur->other_case) + { + const pcre_uint32 *pp = PRIV(ucd_caseless_sets) + ur->caseset; + for (;;) + { + if (c < *pp) return -1; + if (c == *pp++) break; + } + } } } else -#endif #endif /* The same code works when not in UTF-8 mode and in UTF-8 mode when there @@ -206,8 +235,11 @@ if (caseless) { while (length-- > 0) { + pcre_uint32 cc, cp; if (eptr >= md->end_subject) return -2; /* Partial match */ - if (TABLE_GET(*p, md->lcc, *p) != TABLE_GET(*eptr, md->lcc, *eptr)) return -1; + cc = RAWUCHARTEST(eptr); + cp = RAWUCHARTEST(p); + if (TABLE_GET(cp, md->lcc, cp) != TABLE_GET(cc, md->lcc, cc)) return -1; p++; eptr++; } @@ -222,7 +254,7 @@ else while (length-- > 0) { if (eptr >= md->end_subject) return -2; /* Partial match */ - if (*p++ != *eptr++) return -1; + if (RAWUCHARINCTEST(p) != RAWUCHARINCTEST(eptr)) return -1; } } @@ -278,7 +310,7 @@ enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, RM31, RM32, RM33, RM34, RM35, RM36, RM37, RM38, RM39, RM40, RM41, RM42, RM43, RM44, RM45, RM46, RM47, RM48, RM49, RM50, RM51, RM52, RM53, RM54, RM55, RM56, RM57, RM58, RM59, RM60, - RM61, RM62, RM63, RM64, RM65, RM66 }; + RM61, RM62, RM63, RM64, RM65, RM66, RM67 }; /* These versions of the macros use the stack, as normal. There are debugging versions and production versions. Note that the "rw" argument of RMATCH isn't @@ -296,7 +328,7 @@ actually used in this definition. */ } #define RRETURN(ra) \ { \ - printf("match() returned %d from line %d ", ra, __LINE__); \ + printf("match() returned %d from line %d\n", ra, __LINE__); \ return ra; \ } #else @@ -387,7 +419,7 @@ typedef struct heapframe { #ifdef SUPPORT_UCP int Xprop_type; - int Xprop_value; + unsigned int Xprop_value; int Xprop_fail_result; int Xoclength; pcre_uchar Xocchars[6]; @@ -400,10 +432,10 @@ typedef struct heapframe { int Xlength; int Xmax; int Xmin; - int Xnumber; + unsigned int Xnumber; int Xoffset; - int Xop; - int Xsave_capture_last; + unsigned int Xop; + pcre_int32 Xsave_capture_last; int Xsave_offset1, Xsave_offset2, Xsave_offset3; int Xstacksave[REC_STACK_SAVE_MAX]; @@ -488,7 +520,7 @@ so they can be ordinary variables in all cases. Mark some of them with register int rrc; /* Returns from recursive calls */ register int i; /* Used for loops not involving calls to RMATCH() */ -register unsigned int c; /* Character values not kept over RMATCH() calls */ +register pcre_uint32 c; /* Character values not kept over RMATCH() calls */ register BOOL utf; /* Local copy of UTF flag for speed */ BOOL minimize, possessive; /* Quantifier options */ @@ -605,7 +637,7 @@ BOOL prev_is_word; #ifdef SUPPORT_UCP int prop_type; -int prop_value; +unsigned int prop_value; int prop_fail_result; int oclength; pcre_uchar occhars[6]; @@ -616,10 +648,10 @@ int ctype; int length; int max; int min; -int number; +unsigned int number; int offset; -int op; -int save_capture_last; +unsigned int op; +pcre_int32 save_capture_last; int save_offset1, save_offset2, save_offset3; int stacksave[REC_STACK_SAVE_MAX]; @@ -737,7 +769,7 @@ for (;;) unaltered. */ else if (rrc == MATCH_SKIP_ARG && - STRCMP_UC_UC(ecode + 2, md->start_match_ptr) == 0) + STRCMP_UC_UC_TEST(ecode + 2, md->start_match_ptr) == 0) { md->start_match_ptr = eptr; RRETURN(MATCH_SKIP); @@ -747,23 +779,16 @@ for (;;) case OP_FAIL: RRETURN(MATCH_NOMATCH); - /* COMMIT overrides PRUNE, SKIP, and THEN */ - case OP_COMMIT: RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM52); - if (rrc != MATCH_NOMATCH && rrc != MATCH_PRUNE && - rrc != MATCH_SKIP && rrc != MATCH_SKIP_ARG && - rrc != MATCH_THEN) - RRETURN(rrc); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); RRETURN(MATCH_COMMIT); - /* PRUNE overrides THEN */ - case OP_PRUNE: RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM51); - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); RRETURN(MATCH_PRUNE); case OP_PRUNE_ARG: @@ -773,38 +798,39 @@ for (;;) eptrb, RM56); if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) && md->mark == NULL) md->mark = ecode + 2; - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); RRETURN(MATCH_PRUNE); - /* SKIP overrides PRUNE and THEN */ - case OP_SKIP: RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM53); - if (rrc != MATCH_NOMATCH && rrc != MATCH_PRUNE && rrc != MATCH_THEN) - RRETURN(rrc); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->start_match_ptr = eptr; /* Pass back current position */ RRETURN(MATCH_SKIP); /* Note that, for Perl compatibility, SKIP with an argument does NOT set - nomatch_mark. There is a flag that disables this opcode when re-matching a - pattern that ended with a SKIP for which there was not a matching MARK. */ + nomatch_mark. When a pattern match ends with a SKIP_ARG for which there was + not a matching mark, we have to re-run the match, ignoring the SKIP_ARG + that failed and any that precede it (either they also failed, or were not + triggered). To do this, we maintain a count of executed SKIP_ARGs. If a + SKIP_ARG gets to top level, the match is re-run with md->ignore_skip_arg + set to the count of the one that failed. */ case OP_SKIP_ARG: - if (md->ignore_skip_arg) + md->skip_arg_count++; + if (md->skip_arg_count <= md->ignore_skip_arg) { ecode += PRIV(OP_lengths)[*ecode] + ecode[1]; break; } RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md, eptrb, RM57); - if (rrc != MATCH_NOMATCH && rrc != MATCH_PRUNE && rrc != MATCH_THEN) - RRETURN(rrc); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); /* Pass back the current skip name by overloading md->start_match_ptr and returning the special MATCH_SKIP_ARG return code. This will either be caught by a matching MARK, or get to the top, where it causes a rematch - with the md->ignore_skip_arg flag set. */ + with md->ignore_skip_arg set to the value of md->skip_arg_count. */ md->start_match_ptr = ecode + 2; RRETURN(MATCH_SKIP_ARG); @@ -1050,6 +1076,7 @@ for (;;) /* In all other cases, we have to make another call to match(). */ save_mark = md->mark; + save_capture_last = md->capture_last; RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM2); @@ -1081,6 +1108,7 @@ for (;;) ecode += GET(ecode, 1); md->mark = save_mark; if (*ecode != OP_ALT) break; + md->capture_last = save_capture_last; } RRETURN(MATCH_NOMATCH); @@ -1143,6 +1171,7 @@ for (;;) ecode = md->start_code + code_offset; save_capture_last = md->capture_last; matched_once = TRUE; + mstart = md->start_match_ptr; /* In case \K changed it */ continue; } @@ -1202,6 +1231,7 @@ for (;;) POSSESSIVE_NON_CAPTURE: matched_once = FALSE; code_offset = (int)(ecode - md->start_code); + save_capture_last = md->capture_last; for (;;) { @@ -1214,6 +1244,7 @@ for (;;) eptr = md->end_match_ptr; ecode = md->start_code + code_offset; matched_once = TRUE; + mstart = md->start_match_ptr; /* In case \K reset it */ continue; } @@ -1231,6 +1262,7 @@ for (;;) if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += GET(ecode, 1); if (*ecode != OP_ALT) break; + md->capture_last = save_capture_last; } if (matched_once || allow_zero) @@ -1242,243 +1274,167 @@ for (;;) /* Control never reaches here. */ - /* Conditional group: compilation checked that there are no more than - two branches. If the condition is false, skipping the first branch takes us - past the end if there is only one branch, but that's OK because that is - exactly what going to the ket would do. */ + /* Conditional group: compilation checked that there are no more than two + branches. If the condition is false, skipping the first branch takes us + past the end of the item if there is only one branch, but that's exactly + what we want. */ case OP_COND: case OP_SCOND: - codelink = GET(ecode, 1); + + /* The variable codelink will be added to ecode when the condition is + false, to get to the second branch. Setting it to the offset to the ALT + or KET, then incrementing ecode achieves this effect. We now have ecode + pointing to the condition or callout. */ + + codelink = GET(ecode, 1); /* Offset to the second branch */ + ecode += 1 + LINK_SIZE; /* From this opcode */ /* Because of the way auto-callout works during compile, a callout item is inserted between OP_COND and an assertion condition. */ - if (ecode[LINK_SIZE+1] == OP_CALLOUT) + if (*ecode == OP_CALLOUT) { if (PUBL(callout) != NULL) { PUBL(callout_block) cb; cb.version = 2; /* Version 1 of the callout block */ - cb.callout_number = ecode[LINK_SIZE+2]; + cb.callout_number = ecode[1]; cb.offset_vector = md->offset_vector; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 cb.subject = (PCRE_SPTR)md->start_subject; -#else +#elif defined COMPILE_PCRE16 cb.subject = (PCRE_SPTR16)md->start_subject; +#elif defined COMPILE_PCRE32 + cb.subject = (PCRE_SPTR32)md->start_subject; #endif cb.subject_length = (int)(md->end_subject - md->start_subject); cb.start_match = (int)(mstart - md->start_subject); cb.current_position = (int)(eptr - md->start_subject); - cb.pattern_position = GET(ecode, LINK_SIZE + 3); - cb.next_item_length = GET(ecode, 3 + 2*LINK_SIZE); + cb.pattern_position = GET(ecode, 2); + cb.next_item_length = GET(ecode, 2 + LINK_SIZE); cb.capture_top = offset_top/2; - cb.capture_last = md->capture_last; + cb.capture_last = md->capture_last & CAPLMASK; + /* Internal change requires this for API compatibility. */ + if (cb.capture_last == 0) cb.capture_last = -1; cb.callout_data = md->callout_data; cb.mark = md->nomatch_mark; if ((rrc = (*PUBL(callout))(&cb)) > 0) RRETURN(MATCH_NOMATCH); if (rrc < 0) RRETURN(rrc); } + + /* Advance ecode past the callout, so it now points to the condition. We + must adjust codelink so that the value of ecode+codelink is unchanged. */ + ecode += PRIV(OP_lengths)[OP_CALLOUT]; + codelink -= PRIV(OP_lengths)[OP_CALLOUT]; } - condcode = ecode[LINK_SIZE+1]; + /* Test the various possible conditions */ - /* Now see what the actual condition is */ - - if (condcode == OP_RREF || condcode == OP_NRREF) /* Recursion test */ + condition = FALSE; + switch(condcode = *ecode) { - if (md->recursive == NULL) /* Not recursing => FALSE */ + case OP_RREF: /* Numbered group recursion test */ + if (md->recursive != NULL) /* Not recursing => FALSE */ { - condition = FALSE; - ecode += GET(ecode, 1); - } - else - { - int recno = GET2(ecode, LINK_SIZE + 2); /* Recursion group number*/ + unsigned int recno = GET2(ecode, 1); /* Recursion group number*/ condition = (recno == RREF_ANY || recno == md->recursive->group_num); - - /* If the test is for recursion into a specific subpattern, and it is - false, but the test was set up by name, scan the table to see if the - name refers to any other numbers, and test them. The condition is true - if any one is set. */ - - if (!condition && condcode == OP_NRREF) - { - pcre_uchar *slotA = md->name_table; - for (i = 0; i < md->name_count; i++) - { - if (GET2(slotA, 0) == recno) break; - slotA += md->name_entry_size; - } - - /* Found a name for the number - there can be only one; duplicate - names for different numbers are allowed, but not vice versa. First - scan down for duplicates. */ - - if (i < md->name_count) - { - pcre_uchar *slotB = slotA; - while (slotB > md->name_table) - { - slotB -= md->name_entry_size; - if (STRCMP_UC_UC(slotA + IMM2_SIZE, slotB + IMM2_SIZE) == 0) - { - condition = GET2(slotB, 0) == md->recursive->group_num; - if (condition) break; - } - else break; - } - - /* Scan up for duplicates */ - - if (!condition) - { - slotB = slotA; - for (i++; i < md->name_count; i++) - { - slotB += md->name_entry_size; - if (STRCMP_UC_UC(slotA + IMM2_SIZE, slotB + IMM2_SIZE) == 0) - { - condition = GET2(slotB, 0) == md->recursive->group_num; - if (condition) break; - } - else break; - } - } - } - } - - /* Chose branch according to the condition */ - - ecode += condition? 1 + IMM2_SIZE : GET(ecode, 1); } - } + break; - else if (condcode == OP_CREF || condcode == OP_NCREF) /* Group used test */ - { - offset = GET2(ecode, LINK_SIZE+2) << 1; /* Doubled ref number */ - condition = offset < offset_top && md->offset_vector[offset] >= 0; - - /* If the numbered capture is unset, but the reference was by name, - scan the table to see if the name refers to any other numbers, and test - them. The condition is true if any one is set. This is tediously similar - to the code above, but not close enough to try to amalgamate. */ - - if (!condition && condcode == OP_NCREF) + case OP_DNRREF: /* Duplicate named group recursion test */ + if (md->recursive != NULL) { - int refno = offset >> 1; - pcre_uchar *slotA = md->name_table; - - for (i = 0; i < md->name_count; i++) + int count = GET2(ecode, 1 + IMM2_SIZE); + pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size; + while (count-- > 0) { - if (GET2(slotA, 0) == refno) break; - slotA += md->name_entry_size; - } - - /* Found a name for the number - there can be only one; duplicate names - for different numbers are allowed, but not vice versa. First scan down - for duplicates. */ - - if (i < md->name_count) - { - pcre_uchar *slotB = slotA; - while (slotB > md->name_table) - { - slotB -= md->name_entry_size; - if (STRCMP_UC_UC(slotA + IMM2_SIZE, slotB + IMM2_SIZE) == 0) - { - offset = GET2(slotB, 0) << 1; - condition = offset < offset_top && - md->offset_vector[offset] >= 0; - if (condition) break; - } - else break; - } - - /* Scan up for duplicates */ - - if (!condition) - { - slotB = slotA; - for (i++; i < md->name_count; i++) - { - slotB += md->name_entry_size; - if (STRCMP_UC_UC(slotA + IMM2_SIZE, slotB + IMM2_SIZE) == 0) - { - offset = GET2(slotB, 0) << 1; - condition = offset < offset_top && - md->offset_vector[offset] >= 0; - if (condition) break; - } - else break; - } - } + unsigned int recno = GET2(slot, 0); + condition = recno == md->recursive->group_num; + if (condition) break; + slot += md->name_entry_size; } } + break; - /* Chose branch according to the condition */ + case OP_CREF: /* Numbered group used test */ + offset = GET2(ecode, 1) << 1; /* Doubled ref number */ + condition = offset < offset_top && md->offset_vector[offset] >= 0; + break; - ecode += condition? 1 + IMM2_SIZE : GET(ecode, 1); - } + case OP_DNCREF: /* Duplicate named group used test */ + { + int count = GET2(ecode, 1 + IMM2_SIZE); + pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size; + while (count-- > 0) + { + offset = GET2(slot, 0) << 1; + condition = offset < offset_top && md->offset_vector[offset] >= 0; + if (condition) break; + slot += md->name_entry_size; + } + } + break; - else if (condcode == OP_DEF) /* DEFINE - always false */ - { - condition = FALSE; - ecode += GET(ecode, 1); - } + case OP_DEF: /* DEFINE - always false */ + break; - /* The condition is an assertion. Call match() to evaluate it - setting - md->match_function_type to MATCH_CONDASSERT causes it to stop at the end of - an assertion. */ + /* The condition is an assertion. Call match() to evaluate it - setting + md->match_function_type to MATCH_CONDASSERT causes it to stop at the end + of an assertion. */ - else - { + default: md->match_function_type = MATCH_CONDASSERT; - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM3); + RMATCH(eptr, ecode, offset_top, md, NULL, RM3); if (rrc == MATCH_MATCH) { if (md->end_offset_top > offset_top) offset_top = md->end_offset_top; /* Captures may have happened */ condition = TRUE; - ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE + 2); + + /* Advance ecode past the assertion to the start of the first branch, + but adjust it so that the general choosing code below works. */ + + ecode += GET(ecode, 1); while (*ecode == OP_ALT) ecode += GET(ecode, 1); + ecode += 1 + LINK_SIZE - PRIV(OP_lengths)[condcode]; } /* PCRE doesn't allow the effect of (*THEN) to escape beyond an - assertion; it is therefore treated as NOMATCH. */ + assertion; it is therefore treated as NOMATCH. Any other return is an + error. */ else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) { RRETURN(rrc); /* Need braces because of following else */ } - else - { - condition = FALSE; - ecode += codelink; - } + break; } - /* We are now at the branch that is to be obeyed. As there is only one, can - use tail recursion to avoid using another stack frame, except when there is - unlimited repeat of a possibly empty group. In the latter case, a recursive - call to match() is always required, unless the second alternative doesn't - exist, in which case we can just plough on. Note that, for compatibility - with Perl, the | in a conditional group is NOT treated as creating two - alternatives. If a THEN is encountered in the branch, it propagates out to - the enclosing alternative (unless nested in a deeper set of alternatives, - of course). */ + /* Choose branch according to the condition */ - if (condition || *ecode == OP_ALT) + ecode += condition? PRIV(OP_lengths)[condcode] : codelink; + + /* We are now at the branch that is to be obeyed. As there is only one, we + can use tail recursion to avoid using another stack frame, except when + there is unlimited repeat of a possibly empty group. In the latter case, a + recursive call to match() is always required, unless the second alternative + doesn't exist, in which case we can just plough on. Note that, for + compatibility with Perl, the | in a conditional group is NOT treated as + creating two alternatives. If a THEN is encountered in the branch, it + propagates out to the enclosing alternative (unless nested in a deeper set + of alternatives, of course). */ + + if (condition || ecode[-(1+LINK_SIZE)] == OP_ALT) { if (op != OP_SCOND) { - ecode += 1 + LINK_SIZE; goto TAIL_RECURSE; } md->match_function_type = MATCH_CBEGROUP; - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM49); + RMATCH(eptr, ecode, offset_top, md, eptrb, RM49); RRETURN(rrc); } @@ -1486,7 +1442,6 @@ for (;;) else { - ecode += 1 + LINK_SIZE; } break; @@ -1495,7 +1450,7 @@ for (;;) to close any currently open capturing brackets. */ case OP_CLOSE: - number = GET2(ecode, 1); + number = GET2(ecode, 1); /* Must be less than 65536 */ offset = number << 1; #ifdef PCRE_DEBUG @@ -1503,8 +1458,8 @@ for (;;) printf("\n"); #endif - md->capture_last = number; - if (offset >= md->offset_max) md->offset_overflow = TRUE; else + md->capture_last = (md->capture_last & OVFLMASK) | number; + if (offset >= md->offset_max) md->capture_last |= OVFLBIT; else { md->offset_vector[offset] = md->offset_vector[md->offset_end - number]; @@ -1566,28 +1521,49 @@ for (;;) } else condassert = FALSE; + /* Loop for each branch */ + do { RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM4); + + /* A match means that the assertion is true; break out of the loop + that matches its alternatives. */ + if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) { mstart = md->start_match_ptr; /* In case \K reset it */ break; } + + /* If not matched, restore the previous mark setting. */ + md->mark = save_mark; - /* A COMMIT failure must fail the entire assertion, without trying any - subsequent branches. */ + /* See comment in the code for capturing groups above about handling + THEN. */ - if (rrc == MATCH_COMMIT) RRETURN(MATCH_NOMATCH); + if (rrc == MATCH_THEN) + { + next = ecode + GET(ecode,1); + if (md->start_match_ptr < next && + (*ecode == OP_ALT || *next == OP_ALT)) + rrc = MATCH_NOMATCH; + } - /* PCRE does not allow THEN to escape beyond an assertion; it - is treated as NOMATCH. */ + /* Anything other than NOMATCH causes the entire assertion to fail, + passing back the return code. This includes COMMIT, SKIP, PRUNE and an + uncaptured THEN, which means they take their normal effect. This + consistent approach does not always have exactly the same effect as in + Perl. */ - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += GET(ecode, 1); } - while (*ecode == OP_ALT); + while (*ecode == OP_ALT); /* Continue for next alternative */ + + /* If we have tried all the alternative branches, the assertion has + failed. If not, we broke out after a match. */ if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH); @@ -1595,17 +1571,16 @@ for (;;) if (condassert) RRETURN(MATCH_MATCH); - /* Continue from after the assertion, updating the offsets high water - mark, since extracts may have been taken during the assertion. */ + /* Continue from after a successful assertion, updating the offsets high + water mark, since extracts may have been taken during the assertion. */ do ecode += GET(ecode,1); while (*ecode == OP_ALT); ecode += 1 + LINK_SIZE; offset_top = md->end_offset_top; continue; - /* Negative assertion: all branches must fail to match. Encountering SKIP, - PRUNE, or COMMIT means we must assume failure without checking subsequent - branches. */ + /* Negative assertion: all branches must fail to match for the assertion to + succeed. */ case OP_ASSERT_NOT: case OP_ASSERTBACK_NOT: @@ -1617,28 +1592,64 @@ for (;;) } else condassert = FALSE; + /* Loop for each alternative branch. */ + do { RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM5); - md->mark = save_mark; - if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) RRETURN(MATCH_NOMATCH); - if (rrc == MATCH_SKIP || rrc == MATCH_PRUNE || rrc == MATCH_COMMIT) + md->mark = save_mark; /* Always restore the mark setting */ + + switch(rrc) { - do ecode += GET(ecode,1); while (*ecode == OP_ALT); + case MATCH_MATCH: /* A successful match means */ + case MATCH_ACCEPT: /* the assertion has failed. */ + RRETURN(MATCH_NOMATCH); + + case MATCH_NOMATCH: /* Carry on with next branch */ break; + + /* See comment in the code for capturing groups above about handling + THEN. */ + + case MATCH_THEN: + next = ecode + GET(ecode,1); + if (md->start_match_ptr < next && + (*ecode == OP_ALT || *next == OP_ALT)) + { + rrc = MATCH_NOMATCH; + break; + } + /* Otherwise fall through. */ + + /* COMMIT, SKIP, PRUNE, and an uncaptured THEN cause the whole + assertion to fail to match, without considering any more alternatives. + Failing to match means the assertion is true. This is a consistent + approach, but does not always have the same effect as in Perl. */ + + case MATCH_COMMIT: + case MATCH_SKIP: + case MATCH_SKIP_ARG: + case MATCH_PRUNE: + do ecode += GET(ecode,1); while (*ecode == OP_ALT); + goto NEG_ASSERT_TRUE; /* Break out of alternation loop */ + + /* Anything else is an error */ + + default: + RRETURN(rrc); } - /* PCRE does not allow THEN to escape beyond an assertion; it is treated - as NOMATCH. */ + /* Continue with next branch */ - if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); ecode += GET(ecode,1); } while (*ecode == OP_ALT); - if (condassert) RRETURN(MATCH_MATCH); /* Condition assertion */ + /* All branches in the assertion failed to match. */ - ecode += 1 + LINK_SIZE; + NEG_ASSERT_TRUE: + if (condassert) RRETURN(MATCH_MATCH); /* Condition assertion */ + ecode += 1 + LINK_SIZE; /* Continue with current branch */ continue; /* Move the subject pointer back. This occurs only at the start of @@ -1685,10 +1696,12 @@ for (;;) cb.version = 2; /* Version 1 of the callout block */ cb.callout_number = ecode[1]; cb.offset_vector = md->offset_vector; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 cb.subject = (PCRE_SPTR)md->start_subject; -#else +#elif defined COMPILE_PCRE16 cb.subject = (PCRE_SPTR16)md->start_subject; +#elif defined COMPILE_PCRE32 + cb.subject = (PCRE_SPTR32)md->start_subject; #endif cb.subject_length = (int)(md->end_subject - md->start_subject); cb.start_match = (int)(mstart - md->start_subject); @@ -1696,7 +1709,9 @@ for (;;) cb.pattern_position = GET(ecode, 2); cb.next_item_length = GET(ecode, 2 + LINK_SIZE); cb.capture_top = offset_top/2; - cb.capture_last = md->capture_last; + cb.capture_last = md->capture_last & CAPLMASK; + /* Internal change requires this for API compatibility. */ + if (cb.capture_last == 0) cb.capture_last = -1; cb.callout_data = md->callout_data; cb.mark = md->nomatch_mark; if ((rrc = (*PUBL(callout))(&cb)) > 0) RRETURN(MATCH_NOMATCH); @@ -1725,7 +1740,7 @@ for (;;) case OP_RECURSE: { recursion_info *ri; - int recno; + unsigned int recno; callpat = md->start_code + GET(ecode, 1); recno = (callpat == md->start_code)? 0 : @@ -1742,6 +1757,7 @@ for (;;) /* Add to "recursing stack" */ new_recursive.group_num = recno; + new_recursive.saved_capture_last = md->capture_last; new_recursive.subject_position = eptr; new_recursive.prevrec = md->recursive; md->recursive = &new_recursive; @@ -1765,8 +1781,9 @@ for (;;) new_recursive.saved_max * sizeof(int)); /* OK, now we can do the recursion. After processing each alternative, - restore the offset data. If there were nested recursions, md->recursive - might be changed, so reset it before looping. */ + restore the offset data and the last captured value. If there were nested + recursions, md->recursive might be changed, so reset it before looping. + */ DPRINTF(("Recursing into group %d\n", new_recursive.group_num)); cbegroup = (*callpat >= OP_SBRA); @@ -1777,6 +1794,7 @@ for (;;) md, eptrb, RM6); memcpy(md->offset_vector, new_recursive.offset_save, new_recursive.saved_max * sizeof(int)); + md->capture_last = new_recursive.saved_capture_last; md->recursive = new_recursive.prevrec; if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) { @@ -1793,11 +1811,16 @@ for (;;) goto RECURSION_MATCHED; /* Exit loop; end processing */ } - /* PCRE does not allow THEN or COMMIT to escape beyond a recursion; it - is treated as NOMATCH. */ + /* PCRE does not allow THEN, SKIP, PRUNE or COMMIT to escape beyond a + recursion; they cause a NOMATCH for the entire recursion. These codes + are defined in a range that can be tested for. */ - else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN && - rrc != MATCH_COMMIT) + if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX) + RRETURN(MATCH_NOMATCH); + + /* Any return code other than NOMATCH is an error. */ + + if (rrc != MATCH_NOMATCH) { DPRINTF(("Recursion gave error %d\n", rrc)); if (new_recursive.offset_save != stacksave) @@ -1927,8 +1950,8 @@ for (;;) /* Deal with capturing */ - md->capture_last = number; - if (offset >= md->offset_max) md->offset_overflow = TRUE; else + md->capture_last = (md->capture_last & OVFLMASK) | number; + if (offset >= md->offset_max) md->capture_last |= OVFLBIT; else { /* If offset is greater than offset_top, it means that we are "skipping" a capturing group, and that group's offsets must be marked @@ -1984,6 +2007,7 @@ for (;;) if (*ecode == OP_KETRPOS) { + md->start_match_ptr = mstart; /* In case \K reset it */ md->end_match_ptr = eptr; md->end_offset_top = offset_top; RRETURN(MATCH_KETRPOS); @@ -2079,7 +2103,7 @@ for (;;) eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && - *eptr == NLBLOCK->nl[0]) + RAWUCHARTEST(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); @@ -2123,7 +2147,7 @@ for (;;) eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && - *eptr == NLBLOCK->nl[0]) + RAWUCHARTEST(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); @@ -2266,7 +2290,7 @@ for (;;) eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && - *eptr == NLBLOCK->nl[0]) + RAWUCHARTEST(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); @@ -2415,22 +2439,24 @@ for (;;) { default: RRETURN(MATCH_NOMATCH); - case 0x000d: + case CHAR_CR: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); } - else if (*eptr == 0x0a) eptr++; + else if (RAWUCHARTEST(eptr) == CHAR_LF) eptr++; break; - case 0x000a: + case CHAR_LF: break; - case 0x000b: - case 0x000c: - case 0x0085: + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC case 0x2028: case 0x2029: +#endif /* Not EBCDIC */ if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } @@ -2446,27 +2472,8 @@ for (;;) GETCHARINCTEST(c, eptr); switch(c) { + HSPACE_CASES: RRETURN(MATCH_NOMATCH); /* Byte and multibyte cases */ default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - RRETURN(MATCH_NOMATCH); } ecode++; break; @@ -2480,27 +2487,8 @@ for (;;) GETCHARINCTEST(c, eptr); switch(c) { + HSPACE_CASES: break; /* Byte and multibyte cases */ default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - break; } ecode++; break; @@ -2514,15 +2502,8 @@ for (;;) GETCHARINCTEST(c, eptr); switch(c) { + VSPACE_CASES: RRETURN(MATCH_NOMATCH); default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - RRETURN(MATCH_NOMATCH); } ecode++; break; @@ -2536,15 +2517,8 @@ for (;;) GETCHARINCTEST(c, eptr); switch(c) { + VSPACE_CASES: break; default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - break; } ecode++; break; @@ -2562,6 +2536,7 @@ for (;;) } GETCHARINCTEST(c, eptr); { + const pcre_uint32 *cp; const ucd_record *prop = GET_UCD(c); switch(ecode[1]) @@ -2600,19 +2575,24 @@ for (;;) RRETURN(MATCH_NOMATCH); break; - case PT_SPACE: /* Perl space */ - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR) - == (op == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); - break; + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ + case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_VT || - c == CHAR_FF || c == CHAR_CR) - == (op == OP_NOTPROP)) - RRETURN(MATCH_NOMATCH); + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + if (op == OP_NOTPROP) RRETURN(MATCH_NOMATCH); + break; + + default: + if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == + (op == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); + break; + } break; case PT_WORD: @@ -2622,6 +2602,24 @@ for (;;) RRETURN(MATCH_NOMATCH); break; + case PT_CLIST: + cp = PRIV(ucd_caseless_sets) + ecode[2]; + for (;;) + { + if (c < *cp) + { if (op == OP_PROP) { RRETURN(MATCH_NOMATCH); } else break; } + if (c == *cp++) + { if (op == OP_PROP) break; else { RRETURN(MATCH_NOMATCH); } } + } + break; + + case PT_UCNC: + if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || + c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || + c >= 0xe000) == (op == OP_NOTPROP)) + RRETURN(MATCH_NOMATCH); + break; + /* This should never occur */ default: @@ -2641,19 +2639,25 @@ for (;;) SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if (UCD_CATEGORY(c) == ucp_M) RRETURN(MATCH_NOMATCH); - while (eptr < md->end_subject) + else { - int len = 1; - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - if (UCD_CATEGORY(c) != ucp_M) break; - eptr += len; + int lgb, rgb; + GETCHARINCTEST(c, eptr); + lgb = UCD_GRAPHBREAK(c); + while (eptr < md->end_subject) + { + int len = 1; + if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } + rgb = UCD_GRAPHBREAK(c); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + lgb = rgb; + eptr += len; + } } CHECK_PARTIAL(); ecode++; break; -#endif +#endif /* SUPPORT_UCP */ /* Match a back reference, possibly repeatedly. Look past the end of the @@ -2662,15 +2666,7 @@ for (;;) similar code to character type repeats - written out again for speed. However, if the referenced string is the empty string, always treat it as matched, any number of times (otherwise there could be infinite - loops). */ - - case OP_REF: - case OP_REFI: - caseless = op == OP_REFI; - offset = GET2(ecode, 1) << 1; /* Doubled ref number */ - ecode += 1 + IMM2_SIZE; - - /* If the reference is unset, there are two possibilities: + loops). If the reference is unset, there are two possibilities: (a) In the default, Perl-compatible state, set the length negative; this ensures that every attempt at a match fails. We can't just fail @@ -2680,8 +2676,39 @@ for (;;) so that the back reference matches an empty string. Otherwise, set the length to the length of what was matched by the - referenced subpattern. */ + referenced subpattern. + The OP_REF and OP_REFI opcodes are used for a reference to a numbered group + or to a non-duplicated named group. For a duplicated named group, OP_DNREF + and OP_DNREFI are used. In this case we must scan the list of groups to + which the name refers, and use the first one that is set. */ + + case OP_DNREF: + case OP_DNREFI: + caseless = op == OP_DNREFI; + { + int count = GET2(ecode, 1+IMM2_SIZE); + pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size; + ecode += 1 + 2*IMM2_SIZE; + + while (count-- > 0) + { + offset = GET2(slot, 0) << 1; + if (offset < offset_top && md->offset_vector[offset] >= 0) break; + slot += md->name_entry_size; + } + if (count < 0) + length = (md->jscript_compat)? 0 : -1; + else + length = md->offset_vector[offset+1] - md->offset_vector[offset]; + } + goto REF_REPEAT; + + case OP_REF: + case OP_REFI: + caseless = op == OP_REFI; + offset = GET2(ecode, 1) << 1; /* Doubled ref number */ + ecode += 1 + IMM2_SIZE; if (offset >= offset_top || md->offset_vector[offset] < 0) length = (md->jscript_compat)? 0 : -1; else @@ -2689,6 +2716,7 @@ for (;;) /* Set up for repetition, or handle the non-repeated case */ + REF_REPEAT: switch (*ecode) { case OP_CRSTAR: @@ -2837,8 +2865,12 @@ for (;;) case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSPLUS: + case OP_CRPOSQUERY: c = *ecode++ - OP_CRSTAR; - minimize = (c & 1) != 0; + if (c < OP_CRPOSSTAR - OP_CRSTAR) minimize = (c & 1) != 0; + else possessive = TRUE; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; @@ -2846,7 +2878,9 @@ for (;;) case OP_CRRANGE: case OP_CRMINRANGE: + case OP_CRPOSRANGE: minimize = (*ecode == OP_CRMINRANGE); + possessive = (*ecode == OP_CRPOSRANGE); min = GET2(ecode, 1); max = GET2(ecode, 1 + IMM2_SIZE); if (max == 0) max = INT_MAX; @@ -2988,6 +3022,9 @@ for (;;) if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) break; eptr += len; } + + if (possessive) continue; /* No backtracking */ + for (;;) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM18); @@ -3018,6 +3055,9 @@ for (;;) if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) break; eptr++; } + + if (possessive) continue; /* No backtracking */ + while (eptr >= pp) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM19); @@ -3033,9 +3073,10 @@ for (;;) /* Control never gets here */ - /* Match an extended character class. This opcode is encountered only - when UTF-8 mode mode is supported. Nevertheless, we may not be in UTF-8 - mode, because Unicode properties are supported in non-UTF-8 mode. */ + /* Match an extended character class. In the 8-bit library, this opcode is + encountered only when UTF-8 mode mode is supported. In the 16-bit and + 32-bit libraries, codepoints greater than 255 may be encountered even when + UTF is not supported. */ #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: @@ -3051,8 +3092,12 @@ for (;;) case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSPLUS: + case OP_CRPOSQUERY: c = *ecode++ - OP_CRSTAR; - minimize = (c & 1) != 0; + if (c < OP_CRPOSSTAR - OP_CRSTAR) minimize = (c & 1) != 0; + else possessive = TRUE; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; @@ -3060,7 +3105,9 @@ for (;;) case OP_CRRANGE: case OP_CRMINRANGE: + case OP_CRPOSRANGE: minimize = (*ecode == OP_CRMINRANGE); + possessive = (*ecode == OP_CRPOSRANGE); min = GET2(ecode, 1); max = GET2(ecode, 1 + IMM2_SIZE); if (max == 0) max = INT_MAX; @@ -3132,6 +3179,9 @@ for (;;) if (!PRIV(xclass)(c, data, utf)) break; eptr += len; } + + if (possessive) continue; /* No backtracking */ + for(;;) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM21); @@ -3162,7 +3212,7 @@ for (;;) CHECK_PARTIAL(); /* Not SCHECK_PARTIAL() */ RRETURN(MATCH_NOMATCH); } - while (length-- > 0) if (*ecode++ != *eptr++) RRETURN(MATCH_NOMATCH); + while (length-- > 0) if (*ecode++ != RAWUCHARINC(eptr)) RRETURN(MATCH_NOMATCH); } else #endif @@ -3202,8 +3252,8 @@ for (;;) if (fc < 128) { - if (md->lcc[fc] - != TABLE_GET(*eptr, md->lcc, *eptr)) RRETURN(MATCH_NOMATCH); + pcre_uint32 cc = RAWUCHAR(eptr); + if (md->lcc[fc] != TABLE_GET(cc, md->lcc, cc)) RRETURN(MATCH_NOMATCH); ecode++; eptr++; } @@ -3214,7 +3264,7 @@ for (;;) else { - unsigned int dc; + pcre_uint32 dc; GETCHARINC(dc, eptr); ecode += length; @@ -3307,7 +3357,22 @@ for (;;) max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; - /* Common code for all repeated single-character matches. */ + /* Common code for all repeated single-character matches. We first check + for the minimum number of characters. If the minimum equals the maximum, we + are done. Otherwise, if minimizing, check the rest of the pattern for a + match; if there isn't one, advance up to the maximum, one character at a + time. + + If maximizing, advance up to the maximum number of matching characters, + until eptr is past the end of the maximum run. If possessive, we are + then done (no backing up). Otherwise, match at this position; anything + other than no match is immediately returned. For nomatch, back up one + character, unless we are matching \R and the last thing matched was + \r\n, in which case, back up two bytes. When we reach the first optional + character position, we can save stack by doing a tail recurse. + + The various UTF/non-UTF and caseful/caseless cases are handled separately, + for speed. */ REPEATCHAR: #ifdef SUPPORT_UTF @@ -3324,7 +3389,7 @@ for (;;) if (length > 1) { #ifdef SUPPORT_UCP - unsigned int othercase; + pcre_uint32 othercase; if (op >= OP_STARI && /* Caseless */ (othercase = UCD_OTHERCASE(fc)) != fc) oclength = PRIV(ord2utf)(othercase, occhars); @@ -3391,13 +3456,12 @@ for (;;) } } - if (possessive) continue; - + if (possessive) continue; /* No backtracking */ for(;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM23); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr == pp) { RRETURN(MATCH_NOMATCH); } #ifdef SUPPORT_UCP eptr--; BACKCHAR(eptr); @@ -3451,12 +3515,14 @@ for (;;) for (i = 1; i <= min; i++) { + pcre_uint32 cc; /* Faster than pcre_uchar */ if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (fc != *eptr && foc != *eptr) RRETURN(MATCH_NOMATCH); + cc = RAWUCHARTEST(eptr); + if (fc != cc && foc != cc) RRETURN(MATCH_NOMATCH); eptr++; } if (min == max) continue; @@ -3464,6 +3530,7 @@ for (;;) { for (fi = min;; fi++) { + pcre_uint32 cc; /* Faster than pcre_uchar */ RMATCH(eptr, ecode, offset_top, md, eptrb, RM24); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); @@ -3472,7 +3539,8 @@ for (;;) SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (fc != *eptr && foc != *eptr) RRETURN(MATCH_NOMATCH); + cc = RAWUCHARTEST(eptr); + if (fc != cc && foc != cc) RRETURN(MATCH_NOMATCH); eptr++; } /* Control never gets here */ @@ -3482,26 +3550,26 @@ for (;;) pp = eptr; for (i = min; i < max; i++) { + pcre_uint32 cc; /* Faster than pcre_uchar */ if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } - if (fc != *eptr && foc != *eptr) break; + cc = RAWUCHARTEST(eptr); + if (fc != cc && foc != cc) break; eptr++; } - - if (possessive) continue; - - while (eptr >= pp) + if (possessive) continue; /* No backtracking */ + for (;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM25); eptr--; if (rrc != MATCH_NOMATCH) RRETURN(rrc); } - RRETURN(MATCH_NOMATCH); + /* Control never gets here */ } - /* Control never gets here */ } /* Caseful comparisons (includes all multi-byte characters) */ @@ -3515,7 +3583,7 @@ for (;;) SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (fc != *eptr++) RRETURN(MATCH_NOMATCH); + if (fc != RAWUCHARINCTEST(eptr)) RRETURN(MATCH_NOMATCH); } if (min == max) continue; @@ -3532,7 +3600,7 @@ for (;;) SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (fc != *eptr++) RRETURN(MATCH_NOMATCH); + if (fc != RAWUCHARINCTEST(eptr)) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ } @@ -3546,18 +3614,18 @@ for (;;) SCHECK_PARTIAL(); break; } - if (fc != *eptr) break; + if (fc != RAWUCHARTEST(eptr)) break; eptr++; } - if (possessive) continue; - - while (eptr >= pp) + if (possessive) continue; /* No backtracking */ + for (;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM27); eptr--; if (rrc != MATCH_NOMATCH) RRETURN(rrc); } - RRETURN(MATCH_NOMATCH); + /* Control never gets here */ } } /* Control never gets here */ @@ -3575,7 +3643,7 @@ for (;;) #ifdef SUPPORT_UTF if (utf) { - register unsigned int ch, och; + register pcre_uint32 ch, och; ecode++; GETCHARINC(ch, ecode); @@ -3602,7 +3670,7 @@ for (;;) else #endif { - register unsigned int ch = ecode[1]; + register pcre_uint32 ch = ecode[1]; c = *eptr++; if (ch == c || (op == OP_NOTI && TABLE_GET(ch, md->fcc, ch) == c)) RRETURN(MATCH_NOMATCH); @@ -3716,7 +3784,7 @@ for (;;) #ifdef SUPPORT_UTF if (utf) { - register unsigned int d; + register pcre_uint32 d; for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) @@ -3729,7 +3797,7 @@ for (;;) } } else -#endif +#endif /* SUPPORT_UTF */ /* Not UTF mode */ { for (i = 1; i <= min; i++) @@ -3751,7 +3819,7 @@ for (;;) #ifdef SUPPORT_UTF if (utf) { - register unsigned int d; + register pcre_uint32 d; for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM28); @@ -3767,7 +3835,7 @@ for (;;) } } else -#endif +#endif /*SUPPORT_UTF */ /* Not UTF mode */ { for (fi = min;; fi++) @@ -3796,7 +3864,7 @@ for (;;) #ifdef SUPPORT_UTF if (utf) { - register unsigned int d; + register pcre_uint32 d; for (i = min; i < max; i++) { int len = 1; @@ -3809,17 +3877,18 @@ for (;;) if (fc == d || (unsigned int)foc == d) break; eptr += len; } - if (possessive) continue; + if (possessive) continue; /* No backtracking */ for(;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM30); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ + eptr--; BACKCHAR(eptr); } } else -#endif +#endif /* SUPPORT_UTF */ /* Not UTF mode */ { for (i = min; i < max; i++) @@ -3832,18 +3901,17 @@ for (;;) if (fc == *eptr || foc == *eptr) break; eptr++; } - if (possessive) continue; - while (eptr >= pp) + if (possessive) continue; /* No backtracking */ + for (;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM31); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; } } - - RRETURN(MATCH_NOMATCH); + /* Control never gets here */ } - /* Control never gets here */ } /* Caseful comparisons */ @@ -3853,7 +3921,7 @@ for (;;) #ifdef SUPPORT_UTF if (utf) { - register unsigned int d; + register pcre_uint32 d; for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) @@ -3887,7 +3955,7 @@ for (;;) #ifdef SUPPORT_UTF if (utf) { - register unsigned int d; + register pcre_uint32 d; for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM32); @@ -3931,7 +3999,7 @@ for (;;) #ifdef SUPPORT_UTF if (utf) { - register unsigned int d; + register pcre_uint32 d; for (i = min; i < max; i++) { int len = 1; @@ -3944,12 +4012,13 @@ for (;;) if (fc == d) break; eptr += len; } - if (possessive) continue; + if (possessive) continue; /* No backtracking */ for(;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM34); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ + eptr--; BACKCHAR(eptr); } } @@ -3967,16 +4036,16 @@ for (;;) if (fc == *eptr) break; eptr++; } - if (possessive) continue; - while (eptr >= pp) + if (possessive) continue; /* No backtracking */ + for (;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM35); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; } } - - RRETURN(MATCH_NOMATCH); + /* Control never gets here */ } } /* Control never gets here */ @@ -4158,22 +4227,11 @@ for (;;) } break; - case PT_SPACE: /* Perl space */ - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(c, eptr); - if ((UCD_CATEGORY(c) == ucp_Z || c == CHAR_HT || c == CHAR_NL || - c == CHAR_FF || c == CHAR_CR) - == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - break; + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ + case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ for (i = 1; i <= min; i++) { @@ -4183,10 +4241,18 @@ for (;;) RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); - if ((UCD_CATEGORY(c) == ucp_Z || c == CHAR_HT || c == CHAR_NL || - c == CHAR_VT || c == CHAR_FF || c == CHAR_CR) - == prop_fail_result) - RRETURN(MATCH_NOMATCH); + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + if (prop_fail_result) RRETURN(MATCH_NOMATCH); + break; + + default: + if ((UCD_CATEGORY(c) == ucp_Z) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + break; + } } break; @@ -4207,6 +4273,43 @@ for (;;) } break; + case PT_CLIST: + for (i = 1; i <= min; i++) + { + const pcre_uint32 *cp; + if (eptr >= md->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINCTEST(c, eptr); + cp = PRIV(ucd_caseless_sets) + prop_value; + for (;;) + { + if (c < *cp) + { if (prop_fail_result) break; else { RRETURN(MATCH_NOMATCH); } } + if (c == *cp++) + { if (prop_fail_result) { RRETURN(MATCH_NOMATCH); } else break; } + } + } + break; + + case PT_UCNC: + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINCTEST(c, eptr); + if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || + c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || + c >= 0xe000) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + break; + /* This should not occur */ default: @@ -4226,14 +4329,20 @@ for (;;) SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if (UCD_CATEGORY(c) == ucp_M) RRETURN(MATCH_NOMATCH); - while (eptr < md->end_subject) + else { - int len = 1; - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - if (UCD_CATEGORY(c) != ucp_M) break; - eptr += len; + int lgb, rgb; + GETCHARINCTEST(c, eptr); + lgb = UCD_GRAPHBREAK(c); + while (eptr < md->end_subject) + { + int len = 1; + if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } + rgb = UCD_GRAPHBREAK(c); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + lgb = rgb; + eptr += len; + } } CHECK_PARTIAL(); } @@ -4260,7 +4369,7 @@ for (;;) eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && - *eptr == NLBLOCK->nl[0]) + RAWUCHAR(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); @@ -4301,18 +4410,20 @@ for (;;) { default: RRETURN(MATCH_NOMATCH); - case 0x000d: - if (eptr < md->end_subject && *eptr == 0x0a) eptr++; + case CHAR_CR: + if (eptr < md->end_subject && RAWUCHAR(eptr) == CHAR_LF) eptr++; break; - case 0x000a: + case CHAR_LF: break; - case 0x000b: - case 0x000c: - case 0x0085: + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC case 0x2028: case 0x2029: +#endif /* Not EBCDIC */ if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } @@ -4330,27 +4441,8 @@ for (;;) GETCHARINC(c, eptr); switch(c) { + HSPACE_CASES: RRETURN(MATCH_NOMATCH); /* Byte and multibyte cases */ default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - RRETURN(MATCH_NOMATCH); } } break; @@ -4366,27 +4458,8 @@ for (;;) GETCHARINC(c, eptr); switch(c) { + HSPACE_CASES: break; /* Byte and multibyte cases */ default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - break; } } break; @@ -4402,15 +4475,8 @@ for (;;) GETCHARINC(c, eptr); switch(c) { + VSPACE_CASES: RRETURN(MATCH_NOMATCH); default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - RRETURN(MATCH_NOMATCH); } } break; @@ -4426,15 +4492,8 @@ for (;;) GETCHARINC(c, eptr); switch(c) { + VSPACE_CASES: break; default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - break; } } break; @@ -4456,12 +4515,14 @@ for (;;) case OP_DIGIT: for (i = 1; i <= min; i++) { + pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (*eptr >= 128 || (md->ctypes[*eptr] & ctype_digit) == 0) + cc = RAWUCHAR(eptr); + if (cc >= 128 || (md->ctypes[cc] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); eptr++; /* No need to skip more bytes - we know it's a 1-byte character */ @@ -4471,12 +4532,14 @@ for (;;) case OP_NOT_WHITESPACE: for (i = 1; i <= min; i++) { + pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (*eptr < 128 && (md->ctypes[*eptr] & ctype_space) != 0) + cc = RAWUCHAR(eptr); + if (cc < 128 && (md->ctypes[cc] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); eptr++; ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++); @@ -4486,12 +4549,14 @@ for (;;) case OP_WHITESPACE: for (i = 1; i <= min; i++) { + pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (*eptr >= 128 || (md->ctypes[*eptr] & ctype_space) == 0) + cc = RAWUCHAR(eptr); + if (cc >= 128 || (md->ctypes[cc] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); eptr++; /* No need to skip more bytes - we know it's a 1-byte character */ @@ -4501,12 +4566,14 @@ for (;;) case OP_NOT_WORDCHAR: for (i = 1; i <= min; i++) { + pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (*eptr < 128 && (md->ctypes[*eptr] & ctype_word) != 0) + cc = RAWUCHAR(eptr); + if (cc < 128 && (md->ctypes[cc] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); eptr++; ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++); @@ -4516,12 +4583,14 @@ for (;;) case OP_WORDCHAR: for (i = 1; i <= min; i++) { + pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - if (*eptr >= 128 || (md->ctypes[*eptr] & ctype_word) == 0) + cc = RAWUCHAR(eptr); + if (cc >= 128 || (md->ctypes[cc] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); eptr++; /* No need to skip more bytes - we know it's a 1-byte character */ @@ -4592,17 +4661,17 @@ for (;;) { default: RRETURN(MATCH_NOMATCH); - case 0x000d: - if (eptr < md->end_subject && *eptr == 0x0a) eptr++; + case CHAR_CR: + if (eptr < md->end_subject && *eptr == CHAR_LF) eptr++; break; - case 0x000a: + case CHAR_LF: break; - case 0x000b: - case 0x000c: - case 0x0085: -#ifdef COMPILE_PCRE16 + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case 0x2028: case 0x2029: #endif @@ -4623,26 +4692,9 @@ for (;;) switch(*eptr++) { default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ -#ifdef COMPILE_PCRE16 - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ + HSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + HSPACE_MULTIBYTE_CASES: #endif RRETURN(MATCH_NOMATCH); } @@ -4660,26 +4712,9 @@ for (;;) switch(*eptr++) { default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ -#ifdef COMPILE_PCRE16 - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ + HSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + HSPACE_MULTIBYTE_CASES: #endif break; } @@ -4696,17 +4731,12 @@ for (;;) } switch(*eptr++) { - default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ -#ifdef COMPILE_PCRE16 - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ + VSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + VSPACE_MULTIBYTE_CASES: #endif RRETURN(MATCH_NOMATCH); + default: break; } } break; @@ -4722,14 +4752,9 @@ for (;;) switch(*eptr++) { default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ -#ifdef COMPILE_PCRE16 - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ + VSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + VSPACE_MULTIBYTE_CASES: #endif break; } @@ -4947,25 +4972,11 @@ for (;;) } /* Control never gets here */ - case PT_SPACE: /* Perl space */ - for (fi = min;; fi++) - { - RMATCH(eptr, ecode, offset_top, md, eptrb, RM60); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (fi >= max) RRETURN(MATCH_NOMATCH); - if (eptr >= md->end_subject) - { - SCHECK_PARTIAL(); - RRETURN(MATCH_NOMATCH); - } - GETCHARINCTEST(c, eptr); - if ((UCD_CATEGORY(c) == ucp_Z || c == CHAR_HT || c == CHAR_NL || - c == CHAR_FF || c == CHAR_CR) - == prop_fail_result) - RRETURN(MATCH_NOMATCH); - } - /* Control never gets here */ + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ + case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ for (fi = min;; fi++) { @@ -4978,10 +4989,18 @@ for (;;) RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); - if ((UCD_CATEGORY(c) == ucp_Z || c == CHAR_HT || c == CHAR_NL || - c == CHAR_VT || c == CHAR_FF || c == CHAR_CR) - == prop_fail_result) - RRETURN(MATCH_NOMATCH); + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + if (prop_fail_result) RRETURN(MATCH_NOMATCH); + break; + + default: + if ((UCD_CATEGORY(c) == ucp_Z) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + break; + } } /* Control never gets here */ @@ -5007,8 +5026,50 @@ for (;;) } /* Control never gets here */ - /* This should never occur */ + case PT_CLIST: + for (fi = min;; fi++) + { + const pcre_uint32 *cp; + RMATCH(eptr, ecode, offset_top, md, eptrb, RM67); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max) RRETURN(MATCH_NOMATCH); + if (eptr >= md->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINCTEST(c, eptr); + cp = PRIV(ucd_caseless_sets) + prop_value; + for (;;) + { + if (c < *cp) + { if (prop_fail_result) break; else { RRETURN(MATCH_NOMATCH); } } + if (c == *cp++) + { if (prop_fail_result) { RRETURN(MATCH_NOMATCH); } else break; } + } + } + /* Control never gets here */ + case PT_UCNC: + for (fi = min;; fi++) + { + RMATCH(eptr, ecode, offset_top, md, eptrb, RM60); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max) RRETURN(MATCH_NOMATCH); + if (eptr >= md->end_subject) + { + SCHECK_PARTIAL(); + RRETURN(MATCH_NOMATCH); + } + GETCHARINCTEST(c, eptr); + if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || + c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || + c >= 0xe000) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } + /* Control never gets here */ + + /* This should never occur */ default: RRETURN(PCRE_ERROR_INTERNAL); } @@ -5029,14 +5090,20 @@ for (;;) SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } - GETCHARINCTEST(c, eptr); - if (UCD_CATEGORY(c) == ucp_M) RRETURN(MATCH_NOMATCH); - while (eptr < md->end_subject) + else { - int len = 1; - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - if (UCD_CATEGORY(c) != ucp_M) break; - eptr += len; + int lgb, rgb; + GETCHARINCTEST(c, eptr); + lgb = UCD_GRAPHBREAK(c); + while (eptr < md->end_subject) + { + int len = 1; + if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } + rgb = UCD_GRAPHBREAK(c); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + lgb = rgb; + eptr += len; + } } CHECK_PARTIAL(); } @@ -5082,17 +5149,20 @@ for (;;) switch(c) { default: RRETURN(MATCH_NOMATCH); - case 0x000d: - if (eptr < md->end_subject && *eptr == 0x0a) eptr++; - break; - case 0x000a: + case CHAR_CR: + if (eptr < md->end_subject && RAWUCHAR(eptr) == CHAR_LF) eptr++; break; - case 0x000b: - case 0x000c: - case 0x0085: + case CHAR_LF: + break; + + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#ifndef EBCDIC case 0x2028: case 0x2029: +#endif /* Not EBCDIC */ if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } @@ -5101,84 +5171,32 @@ for (;;) case OP_NOT_HSPACE: switch(c) { + HSPACE_CASES: RRETURN(MATCH_NOMATCH); default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - RRETURN(MATCH_NOMATCH); } break; case OP_HSPACE: switch(c) { + HSPACE_CASES: break; default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - break; } break; case OP_NOT_VSPACE: switch(c) { + VSPACE_CASES: RRETURN(MATCH_NOMATCH); default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - RRETURN(MATCH_NOMATCH); } break; case OP_VSPACE: switch(c) { + VSPACE_CASES: break; default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - break; } break; @@ -5256,17 +5274,17 @@ for (;;) switch(c) { default: RRETURN(MATCH_NOMATCH); - case 0x000d: - if (eptr < md->end_subject && *eptr == 0x0a) eptr++; + case CHAR_CR: + if (eptr < md->end_subject && *eptr == CHAR_LF) eptr++; break; - case 0x000a: + case CHAR_LF: break; - case 0x000b: - case 0x000c: - case 0x0085: -#ifdef COMPILE_PCRE16 + case CHAR_VT: + case CHAR_FF: + case CHAR_NEL: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case 0x2028: case 0x2029: #endif @@ -5279,26 +5297,9 @@ for (;;) switch(c) { default: break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ -#ifdef COMPILE_PCRE16 - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ + HSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + HSPACE_MULTIBYTE_CASES: #endif RRETURN(MATCH_NOMATCH); } @@ -5308,26 +5309,9 @@ for (;;) switch(c) { default: RRETURN(MATCH_NOMATCH); - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ -#ifdef COMPILE_PCRE16 - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ + HSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + HSPACE_MULTIBYTE_CASES: #endif break; } @@ -5337,14 +5321,9 @@ for (;;) switch(c) { default: break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ -#ifdef COMPILE_PCRE16 - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ + VSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + VSPACE_MULTIBYTE_CASES: #endif RRETURN(MATCH_NOMATCH); } @@ -5354,14 +5333,9 @@ for (;;) switch(c) { default: RRETURN(MATCH_NOMATCH); - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ -#ifdef COMPILE_PCRE16 - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ + VSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + VSPACE_MULTIBYTE_CASES: #endif break; } @@ -5510,24 +5484,11 @@ for (;;) } break; - case PT_SPACE: /* Perl space */ - for (i = min; i < max; i++) - { - int len = 1; - if (eptr >= md->end_subject) - { - SCHECK_PARTIAL(); - break; - } - GETCHARLENTEST(c, eptr, len); - if ((UCD_CATEGORY(c) == ucp_Z || c == CHAR_HT || c == CHAR_NL || - c == CHAR_FF || c == CHAR_CR) - == prop_fail_result) - break; - eptr+= len; - } - break; + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ + case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ for (i = min; i < max; i++) { @@ -5538,12 +5499,21 @@ for (;;) break; } GETCHARLENTEST(c, eptr, len); - if ((UCD_CATEGORY(c) == ucp_Z || c == CHAR_HT || c == CHAR_NL || - c == CHAR_VT || c == CHAR_FF || c == CHAR_CR) - == prop_fail_result) + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + if (prop_fail_result) goto ENDLOOP99; /* Break the loop */ break; + + default: + if ((UCD_CATEGORY(c) == ucp_Z) == prop_fail_result) + goto ENDLOOP99; /* Break the loop */ + break; + } eptr+= len; } + ENDLOOP99: break; case PT_WORD: @@ -5565,66 +5535,133 @@ for (;;) } break; + case PT_CLIST: + for (i = min; i < max; i++) + { + const pcre_uint32 *cp; + int len = 1; + if (eptr >= md->end_subject) + { + SCHECK_PARTIAL(); + break; + } + GETCHARLENTEST(c, eptr, len); + cp = PRIV(ucd_caseless_sets) + prop_value; + for (;;) + { + if (c < *cp) + { if (prop_fail_result) break; else goto GOT_MAX; } + if (c == *cp++) + { if (prop_fail_result) goto GOT_MAX; else break; } + } + eptr += len; + } + GOT_MAX: + break; + + case PT_UCNC: + for (i = min; i < max; i++) + { + int len = 1; + if (eptr >= md->end_subject) + { + SCHECK_PARTIAL(); + break; + } + GETCHARLENTEST(c, eptr, len); + if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || + c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || + c >= 0xe000) == prop_fail_result) + break; + eptr += len; + } + break; + default: RRETURN(PCRE_ERROR_INTERNAL); } /* eptr is now past the end of the maximum run */ - if (possessive) continue; + if (possessive) continue; /* No backtracking */ for(;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM44); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ + eptr--; if (utf) BACKCHAR(eptr); } } - /* Match extended Unicode sequences. We will get here only if the + /* Match extended Unicode grapheme clusters. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ else if (ctype == OP_EXTUNI) { for (i = min; i < max; i++) { - int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - if (UCD_CATEGORY(c) == ucp_M) break; - eptr += len; - while (eptr < md->end_subject) + else { - len = 1; - if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } - if (UCD_CATEGORY(c) != ucp_M) break; - eptr += len; + int lgb, rgb; + GETCHARINCTEST(c, eptr); + lgb = UCD_GRAPHBREAK(c); + while (eptr < md->end_subject) + { + int len = 1; + if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } + rgb = UCD_GRAPHBREAK(c); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + lgb = rgb; + eptr += len; + } } CHECK_PARTIAL(); } /* eptr is now past the end of the maximum run */ - if (possessive) continue; + if (possessive) continue; /* No backtracking */ for(;;) { + int lgb, rgb; + PCRE_PUCHAR fptr; + + if (eptr == pp) goto TAIL_RECURSE; /* At start of char run */ RMATCH(eptr, ecode, offset_top, md, eptrb, RM45); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ - for (;;) /* Move back over one extended */ + + /* Backtracking over an extended grapheme cluster involves inspecting + the previous two characters (if present) to see if a break is + permitted between them. */ + + eptr--; + if (!utf) c = *eptr; else { - if (!utf) c = *eptr; else + BACKCHAR(eptr); + GETCHAR(c, eptr); + } + rgb = UCD_GRAPHBREAK(c); + + for (;;) + { + if (eptr == pp) goto TAIL_RECURSE; /* At start of char run */ + fptr = eptr - 1; + if (!utf) c = *fptr; else { - BACKCHAR(eptr); - GETCHAR(c, eptr); + BACKCHAR(fptr); + GETCHAR(c, fptr); } - if (UCD_CATEGORY(c) != ucp_M) break; - eptr--; + lgb = UCD_GRAPHBREAK(c); + if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; + eptr = fptr; + rgb = lgb; } } } @@ -5652,7 +5689,7 @@ for (;;) eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && - *eptr == NLBLOCK->nl[0]) + RAWUCHAR(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); @@ -5678,7 +5715,7 @@ for (;;) eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && - *eptr == NLBLOCK->nl[0]) + RAWUCHAR(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); @@ -5732,17 +5769,20 @@ for (;;) break; } GETCHARLEN(c, eptr, len); - if (c == 0x000d) + if (c == CHAR_CR) { if (++eptr >= md->end_subject) break; - if (*eptr == 0x000a) eptr++; + if (RAWUCHAR(eptr) == CHAR_LF) eptr++; } else { - if (c != 0x000a && + if (c != CHAR_LF && (md->bsr_anycrlf || - (c != 0x000b && c != 0x000c && - c != 0x0085 && c != 0x2028 && c != 0x2029))) + (c != CHAR_VT && c != CHAR_FF && c != CHAR_NEL +#ifndef EBCDIC + && c != 0x2028 && c != 0x2029 +#endif /* Not EBCDIC */ + ))) break; eptr += len; } @@ -5763,28 +5803,8 @@ for (;;) GETCHARLEN(c, eptr, len); switch(c) { + HSPACE_CASES: gotspace = TRUE; break; default: gotspace = FALSE; break; - case 0x09: /* HT */ - case 0x20: /* SPACE */ - case 0xa0: /* NBSP */ - case 0x1680: /* OGHAM SPACE MARK */ - case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ - case 0x2000: /* EN QUAD */ - case 0x2001: /* EM QUAD */ - case 0x2002: /* EN SPACE */ - case 0x2003: /* EM SPACE */ - case 0x2004: /* THREE-PER-EM SPACE */ - case 0x2005: /* FOUR-PER-EM SPACE */ - case 0x2006: /* SIX-PER-EM SPACE */ - case 0x2007: /* FIGURE SPACE */ - case 0x2008: /* PUNCTUATION SPACE */ - case 0x2009: /* THIN SPACE */ - case 0x200A: /* HAIR SPACE */ - case 0x202f: /* NARROW NO-BREAK SPACE */ - case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ - case 0x3000: /* IDEOGRAPHIC SPACE */ - gotspace = TRUE; - break; } if (gotspace == (ctype == OP_NOT_HSPACE)) break; eptr += len; @@ -5805,16 +5825,8 @@ for (;;) GETCHARLEN(c, eptr, len); switch(c) { + VSPACE_CASES: gotspace = TRUE; break; default: gotspace = FALSE; break; - case 0x0a: /* LF */ - case 0x0b: /* VT */ - case 0x0c: /* FF */ - case 0x0d: /* CR */ - case 0x85: /* NEL */ - case 0x2028: /* LINE SEPARATOR */ - case 0x2029: /* PARAGRAPH SEPARATOR */ - gotspace = TRUE; - break; } if (gotspace == (ctype == OP_NOT_VSPACE)) break; eptr += len; @@ -5915,21 +5927,16 @@ for (;;) RRETURN(PCRE_ERROR_INTERNAL); } - /* eptr is now past the end of the maximum run. If possessive, we are - done (no backing up). Otherwise, match at this position; anything other - than no match is immediately returned. For nomatch, back up one - character, unless we are matching \R and the last thing matched was - \r\n, in which case, back up two bytes. */ - - if (possessive) continue; + if (possessive) continue; /* No backtracking */ for(;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM46); if (rrc != MATCH_NOMATCH) RRETURN(rrc); - if (eptr-- == pp) break; /* Stop if tried at original pos */ + eptr--; BACKCHAR(eptr); - if (ctype == OP_ANYNL && eptr > pp && *eptr == '\n' && - eptr[-1] == '\r') eptr--; + if (ctype == OP_ANYNL && eptr > pp && RAWUCHAR(eptr) == CHAR_NL && + RAWUCHAR(eptr - 1) == CHAR_CR) eptr--; } } else @@ -5980,19 +5987,19 @@ for (;;) break; } c = *eptr; - if (c == 0x000d) + if (c == CHAR_CR) { if (++eptr >= md->end_subject) break; - if (*eptr == 0x000a) eptr++; + if (*eptr == CHAR_LF) eptr++; } else { - if (c != 0x000a && (md->bsr_anycrlf || - (c != 0x000b && c != 0x000c && c != 0x0085 -#ifdef COMPILE_PCRE16 - && c != 0x2028 && c != 0x2029 + if (c != CHAR_LF && (md->bsr_anycrlf || + (c != CHAR_VT && c != CHAR_FF && c != CHAR_NEL +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + && c != 0x2028 && c != 0x2029 #endif - ))) break; + ))) break; eptr++; } } @@ -6006,15 +6013,17 @@ for (;;) SCHECK_PARTIAL(); break; } - c = *eptr; - if (c == 0x09 || c == 0x20 || c == 0xa0 -#ifdef COMPILE_PCRE16 - || c == 0x1680 || c == 0x180e || (c >= 0x2000 && c <= 0x200A) - || c == 0x202f || c == 0x205f || c == 0x3000 + switch(*eptr) + { + default: eptr++; break; + HSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + HSPACE_MULTIBYTE_CASES: #endif - ) break; - eptr++; + goto ENDLOOP00; + } } + ENDLOOP00: break; case OP_HSPACE: @@ -6025,15 +6034,17 @@ for (;;) SCHECK_PARTIAL(); break; } - c = *eptr; - if (c != 0x09 && c != 0x20 && c != 0xa0 -#ifdef COMPILE_PCRE16 - && c != 0x1680 && c != 0x180e && (c < 0x2000 || c > 0x200A) - && c != 0x202f && c != 0x205f && c != 0x3000 + switch(*eptr) + { + default: goto ENDLOOP01; + HSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + HSPACE_MULTIBYTE_CASES: #endif - ) break; - eptr++; + eptr++; break; + } } + ENDLOOP01: break; case OP_NOT_VSPACE: @@ -6044,14 +6055,17 @@ for (;;) SCHECK_PARTIAL(); break; } - c = *eptr; - if (c == 0x0a || c == 0x0b || c == 0x0c || c == 0x0d || c == 0x85 -#ifdef COMPILE_PCRE16 - || c == 0x2028 || c == 0x2029 + switch(*eptr) + { + default: eptr++; break; + VSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + VSPACE_MULTIBYTE_CASES: #endif - ) break; - eptr++; + goto ENDLOOP02; + } } + ENDLOOP02: break; case OP_VSPACE: @@ -6062,14 +6076,17 @@ for (;;) SCHECK_PARTIAL(); break; } - c = *eptr; - if (c != 0x0a && c != 0x0b && c != 0x0c && c != 0x0d && c != 0x85 -#ifdef COMPILE_PCRE16 - && c != 0x2028 && c != 0x2029 + switch(*eptr) + { + default: goto ENDLOOP03; + VSPACE_BYTE_CASES: +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + VSPACE_MULTIBYTE_CASES: #endif - ) break; - eptr++; + eptr++; break; + } } + ENDLOOP03: break; case OP_NOT_DIGIT: @@ -6154,28 +6171,20 @@ for (;;) RRETURN(PCRE_ERROR_INTERNAL); } - /* eptr is now past the end of the maximum run. If possessive, we are - done (no backing up). Otherwise, match at this position; anything other - than no match is immediately returned. For nomatch, back up one - character (byte), unless we are matching \R and the last thing matched - was \r\n, in which case, back up two bytes. */ - - if (possessive) continue; - while (eptr >= pp) + if (possessive) continue; /* No backtracking */ + for (;;) { + if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM47); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; - if (ctype == OP_ANYNL && eptr > pp && *eptr == '\n' && - eptr[-1] == '\r') eptr--; + if (ctype == OP_ANYNL && eptr > pp && *eptr == CHAR_LF && + eptr[-1] == CHAR_CR) eptr--; } } - /* Get here if we can't make it match with any permitted repetitions */ - - RRETURN(MATCH_NOMATCH); + /* Control never gets here */ } - /* Control never gets here */ /* There's been some horrible disaster. Arrival here can only mean there is something seriously wrong in the code above or the OP_xxx definitions. */ @@ -6209,22 +6218,19 @@ switch (frame->Xwhere) LBL(53) LBL(54) LBL(55) LBL(56) LBL(57) LBL(58) LBL(63) LBL(64) LBL(65) LBL(66) #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 - LBL(21) + LBL(20) LBL(21) #endif #ifdef SUPPORT_UTF - LBL(16) LBL(18) LBL(20) + LBL(16) LBL(18) LBL(22) LBL(23) LBL(28) LBL(30) LBL(32) LBL(34) LBL(42) LBL(46) #ifdef SUPPORT_UCP LBL(36) LBL(37) LBL(38) LBL(39) LBL(40) LBL(41) LBL(44) LBL(45) - LBL(59) LBL(60) LBL(61) LBL(62) + LBL(59) LBL(60) LBL(61) LBL(62) LBL(67) #endif /* SUPPORT_UCP */ #endif /* SUPPORT_UTF */ default: DPRINTF(("jump error in pcre match: label %d non-existent\n", frame->Xwhere)); - -printf("+++jump error in pcre match: label %d non-existent\n", frame->Xwhere); - return PCRE_ERROR_INTERNAL; } #undef LBL @@ -6336,16 +6342,21 @@ Returns: > 0 => success; value is the number of elements filled in < -1 => some kind of unexpected problem */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_exec(const pcre *argument_re, const pcre_extra *extra_data, PCRE_SPTR subject, int length, int start_offset, int options, int *offsets, int offsetcount) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_exec(const pcre16 *argument_re, const pcre16_extra *extra_data, PCRE_SPTR16 subject, int length, int start_offset, int options, int *offsets, int offsetcount) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_exec(const pcre32 *argument_re, const pcre32_extra *extra_data, + PCRE_SPTR32 subject, int length, int start_offset, int options, int *offsets, + int offsetcount) #endif { int rc, ocount, arg_offset_max; @@ -6368,6 +6379,7 @@ const pcre_uint8 *start_bits = NULL; PCRE_PUCHAR start_match = (PCRE_PUCHAR)subject + start_offset; PCRE_PUCHAR end_subject; PCRE_PUCHAR start_partial = NULL; +PCRE_PUCHAR match_partial = NULL; PCRE_PUCHAR req_char_ptr = start_match - 1; const pcre_study_data *study; @@ -6399,6 +6411,7 @@ if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; if (re == NULL || subject == NULL || (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; if (offsetcount < 0) return PCRE_ERROR_BADCOUNT; +if (length < 0) return PCRE_ERROR_BADLENGTH; if (start_offset < 0 || start_offset > length) return PCRE_ERROR_BADOFFSET; /* Check that the first field in the block is the magic number. If it is not, @@ -6436,19 +6449,22 @@ if (utf && (options & PCRE_NO_UTF8_CHECK) == 0) offsets[0] = erroroffset; offsets[1] = errorcode; } -#ifdef COMPILE_PCRE16 - return (errorcode <= PCRE_UTF16_ERR1 && md->partial > 1)? - PCRE_ERROR_SHORTUTF16 : PCRE_ERROR_BADUTF16; -#else +#if defined COMPILE_PCRE8 return (errorcode <= PCRE_UTF8_ERR5 && md->partial > 1)? PCRE_ERROR_SHORTUTF8 : PCRE_ERROR_BADUTF8; +#elif defined COMPILE_PCRE16 + return (errorcode <= PCRE_UTF16_ERR1 && md->partial > 1)? + PCRE_ERROR_SHORTUTF16 : PCRE_ERROR_BADUTF16; +#elif defined COMPILE_PCRE32 + return PCRE_ERROR_BADUTF32; #endif } - +#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 /* Check that a start_offset points to the start of a UTF character. */ if (start_offset > 0 && start_offset < length && NOT_FIRSTCHAR(((PCRE_PUCHAR)subject)[start_offset])) return PCRE_ERROR_BADUTF8_OFFSET; +#endif } #endif @@ -6462,17 +6478,15 @@ if (extra_data != NULL && (extra_data->flags & (PCRE_EXTRA_EXECUTABLE_JIT | PCRE_EXTRA_TABLES)) == PCRE_EXTRA_EXECUTABLE_JIT && extra_data->executable_jit != NULL - && (options & ~(PCRE_NO_UTF8_CHECK | PCRE_NOTBOL | PCRE_NOTEOL | - PCRE_NOTEMPTY | PCRE_NOTEMPTY_ATSTART | - PCRE_PARTIAL_SOFT | PCRE_PARTIAL_HARD)) == 0) + && (options & ~PUBLIC_JIT_EXEC_OPTIONS) == 0) { - rc = PRIV(jit_exec)(re, extra_data, (const pcre_uchar *)subject, length, + rc = PRIV(jit_exec)(extra_data, (const pcre_uchar *)subject, length, start_offset, options, 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; + if (rc != PCRE_ERROR_JIT_BADOPTION) return rc; } #endif @@ -6495,6 +6509,8 @@ md->callout_data = NULL; tables = re->tables; +/* The two limit values override the defaults, whatever their value. */ + if (extra_data != NULL) { register unsigned int flags = extra_data->flags; @@ -6509,6 +6525,15 @@ if (extra_data != NULL) if ((flags & PCRE_EXTRA_TABLES) != 0) tables = extra_data->tables; } +/* Limits in the regex override only if they are smaller. */ + +if ((re->flags & PCRE_MLSET) != 0 && re->limit_match < md->match_limit) + md->match_limit = re->limit_match; + +if ((re->flags & PCRE_RLSET) != 0 && + re->limit_recursion < md->match_limit_recursion) + md->match_limit_recursion = re->limit_recursion; + /* If the exec call supplied NULL for tables, use the inbuilt ones. This is a feature that makes it possible to save compiled regex and re-use them in other programs later. */ @@ -6534,7 +6559,7 @@ end_subject = md->end_subject; md->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; md->use_ucp = (re->options & PCRE_UCP) != 0; md->jscript_compat = (re->options & PCRE_JAVASCRIPT_COMPAT) != 0; -md->ignore_skip_arg = FALSE; +md->ignore_skip_arg = 0; /* Some options are unpacked into BOOL variables in the hope that testing them will be faster than individual option bits. */ @@ -6644,11 +6669,9 @@ if (re->top_backref > 0 && re->top_backref >= ocount/3) DPRINTF(("Got memory to hold back references\n")); } else md->offset_vector = offsets; - md->offset_end = ocount; md->offset_max = (2*ocount)/3; -md->offset_overflow = FALSE; -md->capture_last = -1; +md->capture_last = 0; /* Reset the working variable associated with each extraction. These should never be used unless previously set, but they get saved and restored, and so we @@ -6756,12 +6779,14 @@ for(;;) if (has_first_char) { + pcre_uchar smc; + if (first_char != first_char2) while (start_match < end_subject && - *start_match != first_char && *start_match != first_char2) + (smc = RAWUCHARTEST(start_match)) != first_char && smc != first_char2) start_match++; else - while (start_match < end_subject && *start_match != first_char) + while (start_match < end_subject && RAWUCHARTEST(start_match) != first_char) start_match++; } @@ -6793,7 +6818,7 @@ for(;;) if (start_match[-1] == CHAR_CR && (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) && start_match < end_subject && - *start_match == CHAR_NL) + RAWUCHARTEST(start_match) == CHAR_NL) start_match++; } } @@ -6804,7 +6829,7 @@ for(;;) { while (start_match < end_subject) { - register unsigned int c = *start_match; + register pcre_uint32 c = RAWUCHARTEST(start_match); #ifndef COMPILE_PCRE8 if (c > 255) c = 255; #endif @@ -6872,7 +6897,7 @@ for(;;) { while (p < end_subject) { - register int pp = *p++; + register pcre_uint32 pp = RAWUCHARINCTEST(p); if (pp == req_char || pp == req_char2) { p--; break; } } } @@ -6880,7 +6905,7 @@ for(;;) { while (p < end_subject) { - if (*p++ == req_char) { p--; break; } + if (RAWUCHARINCTEST(p) == req_char) { p--; break; } } } @@ -6916,8 +6941,13 @@ for(;;) md->match_call_count = 0; md->match_function_type = 0; md->end_offset_top = 0; + md->skip_arg_count = 0; rc = match(start_match, md->start_code, start_match, 2, md, NULL, 0); - if (md->hitend && start_partial == NULL) start_partial = md->start_used_ptr; + if (md->hitend && start_partial == NULL) + { + start_partial = md->start_used_ptr; + match_partial = start_match; + } switch(rc) { @@ -6930,14 +6960,14 @@ for(;;) case MATCH_SKIP_ARG: new_start_match = start_match; - md->ignore_skip_arg = TRUE; + md->ignore_skip_arg = md->skip_arg_count; break; - /* SKIP passes back the next starting point explicitly, but if it is the - same as the match we have just done, treat it as NOMATCH. */ + /* SKIP passes back the next starting point explicitly, but if it is no + greater than the match we have just done, treat it as NOMATCH. */ case MATCH_SKIP: - if (md->start_match_ptr != start_match) + if (md->start_match_ptr > start_match) { new_start_match = md->start_match_ptr; break; @@ -6945,12 +6975,12 @@ for(;;) /* Fall through */ /* NOMATCH and PRUNE advance by one character. THEN at this level acts - exactly like PRUNE. Unset the ignore SKIP-with-argument flag. */ + exactly like PRUNE. Unset ignore SKIP-with-argument. */ case MATCH_NOMATCH: case MATCH_PRUNE: case MATCH_THEN: - md->ignore_skip_arg = FALSE; + md->ignore_skip_arg = 0; new_start_match = start_match + 1; #ifdef SUPPORT_UTF if (utf) @@ -7043,7 +7073,7 @@ if (rc == MATCH_MATCH || rc == MATCH_ACCEPT) (arg_offset_max - 2) * sizeof(int)); DPRINTF(("Copied offsets from temporary memory\n")); } - if (md->end_offset_top > arg_offset_max) md->offset_overflow = TRUE; + if (md->end_offset_top > arg_offset_max) md->capture_last |= OVFLBIT; DPRINTF(("Freeing temporary memory\n")); (PUBL(free))(md->offset_vector); } @@ -7051,7 +7081,8 @@ if (rc == MATCH_MATCH || rc == MATCH_ACCEPT) /* Set the return code to the number of captured strings, or 0 if there were too many to fit into the vector. */ - rc = (md->offset_overflow && md->end_offset_top >= arg_offset_max)? + rc = ((md->capture_last & OVFLBIT) != 0 && + md->end_offset_top >= arg_offset_max)? 0 : md->end_offset_top/2; /* If there is space in the offset vector, set any unused pairs at the end of @@ -7116,7 +7147,7 @@ if (rc != MATCH_NOMATCH && rc != PCRE_ERROR_PARTIAL) /* Handle partial matches - disable any mark data */ -if (start_partial != NULL) +if (match_partial != NULL) { DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n")); md->mark = NULL; @@ -7124,6 +7155,8 @@ if (start_partial != NULL) { offsets[0] = (int)(start_partial - (PCRE_PUCHAR)subject); offsets[1] = (int)(end_subject - (PCRE_PUCHAR)subject); + if (offsetcount > 2) + offsets[2] = (int)(match_partial - (PCRE_PUCHAR)subject); } rc = PCRE_ERROR_PARTIAL; } diff --git a/src/3rd/pcre/pcrefinf.c b/src/3rd/pcre/pcrefinf.c index 0f0beba1d1..3b6bbe9d65 100644 --- a/src/3rd/pcre/pcrefinf.c +++ b/src/3rd/pcre/pcrefinf.c @@ -6,7 +6,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2012 University of Cambridge + Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -65,14 +65,18 @@ Arguments: Returns: 0 if data returned, negative on error */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_fullinfo(const pcre *argument_re, const pcre_extra *extra_data, int what, void *where) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_fullinfo(const pcre16 *argument_re, const pcre16_extra *extra_data, int what, void *where) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_fullinfo(const pcre32 *argument_re, const pcre32_extra *extra_data, + int what, void *where) #endif { const REAL_PCRE *re = (const REAL_PCRE *)argument_re; @@ -132,10 +136,21 @@ switch (what) case PCRE_INFO_FIRSTBYTE: *((int *)where) = - ((re->flags & PCRE_FIRSTSET) != 0)? re->first_char : + ((re->flags & PCRE_FIRSTSET) != 0)? (int)re->first_char : ((re->flags & PCRE_STARTLINE) != 0)? -1 : -2; break; + case PCRE_INFO_FIRSTCHARACTER: + *((pcre_uint32 *)where) = + (re->flags & PCRE_FIRSTSET) != 0 ? re->first_char : 0; + break; + + case PCRE_INFO_FIRSTCHARACTERFLAGS: + *((int *)where) = + ((re->flags & PCRE_FIRSTSET) != 0) ? 1 : + ((re->flags & PCRE_STARTLINE) != 0) ? 2 : 0; + break; + /* Make sure we pass back the pointer to the bit vector in the external block, not the internal copy (with flipped integer fields). */ @@ -159,9 +174,19 @@ switch (what) case PCRE_INFO_LASTLITERAL: *((int *)where) = - ((re->flags & PCRE_REQCHSET) != 0)? re->req_char : -1; + ((re->flags & PCRE_REQCHSET) != 0)? (int)re->req_char : -1; break; + case PCRE_INFO_REQUIREDCHAR: + *((pcre_uint32 *)where) = + ((re->flags & PCRE_REQCHSET) != 0) ? re->req_char : 0; + break; + + case PCRE_INFO_REQUIREDCHARFLAGS: + *((int *)where) = + ((re->flags & PCRE_REQCHSET) != 0); + break; + case PCRE_INFO_NAMEENTRYSIZE: *((int *)where) = re->name_entry_size; break; @@ -197,6 +222,20 @@ switch (what) *((int *)where) = re->max_lookbehind; break; + case PCRE_INFO_MATCHLIMIT: + if ((re->flags & PCRE_MLSET) == 0) return PCRE_ERROR_UNSET; + *((pcre_uint32 *)where) = re->limit_match; + break; + + case PCRE_INFO_RECURSIONLIMIT: + if ((re->flags & PCRE_RLSET) == 0) return PCRE_ERROR_UNSET; + *((pcre_uint32 *)where) = re->limit_recursion; + break; + + case PCRE_INFO_MATCH_EMPTY: + *((int *)where) = (re->flags & PCRE_MATCH_EMPTY) != 0; + break; + default: return PCRE_ERROR_BADOPTION; } diff --git a/src/3rd/pcre/pcreget.c b/src/3rd/pcre/pcreget.c index 07617fe53f..8e2c82c0dd 100644 --- a/src/3rd/pcre/pcreget.c +++ b/src/3rd/pcre/pcreget.c @@ -65,12 +65,15 @@ Returns: the number of the named parentheses, or a negative number (PCRE_ERROR_NOSUBSTRING) if not found */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_stringnumber(const pcre *code, const char *stringname) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_stringnumber(const pcre16 *code, PCRE_SPTR16 stringname) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_get_stringnumber(const pcre32 *code, PCRE_SPTR32 stringname) #endif { int rc; @@ -98,6 +101,16 @@ if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0 if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) return rc; #endif +#ifdef COMPILE_PCRE32 +if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) + return rc; +if (top <= 0) return PCRE_ERROR_NOSUBSTRING; + +if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) + return rc; +if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) + return rc; +#endif bot = 0; while (top > bot) @@ -132,14 +145,18 @@ Returns: the length of each entry, or a negative number (PCRE_ERROR_NOSUBSTRING) if not found */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_stringtable_entries(const pcre *code, const char *stringname, char **firstptr, char **lastptr) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_stringtable_entries(const pcre16 *code, PCRE_SPTR16 stringname, PCRE_UCHAR16 **firstptr, PCRE_UCHAR16 **lastptr) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_get_stringtable_entries(const pcre32 *code, PCRE_SPTR32 stringname, + PCRE_UCHAR32 **firstptr, PCRE_UCHAR32 **lastptr) #endif { int rc; @@ -167,6 +184,16 @@ if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0 if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) return rc; #endif +#ifdef COMPILE_PCRE32 +if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) + return rc; +if (top <= 0) return PCRE_ERROR_NOSUBSTRING; + +if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) + return rc; +if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) + return rc; +#endif lastentry = nametable + entrysize * (top - 1); bot = 0; @@ -192,12 +219,15 @@ while (top > bot) (pcre_uchar *)(last + entrysize + IMM2_SIZE)) != 0) break; last += entrysize; } -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 *firstptr = (char *)first; *lastptr = (char *)last; -#else +#elif defined COMPILE_PCRE16 *firstptr = (PCRE_UCHAR16 *)first; *lastptr = (PCRE_UCHAR16 *)last; +#elif defined COMPILE_PCRE32 + *firstptr = (PCRE_UCHAR32 *)first; + *lastptr = (PCRE_UCHAR32 *)last; #endif return entrysize; } @@ -226,31 +256,40 @@ Returns: the number of the first that is set, or a negative number on error */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 static int get_first_set(const pcre *code, const char *stringname, int *ovector) -#else +#elif defined COMPILE_PCRE16 static int get_first_set(const pcre16 *code, PCRE_SPTR16 stringname, int *ovector) +#elif defined COMPILE_PCRE32 +static int +get_first_set(const pcre32 *code, PCRE_SPTR32 stringname, int *ovector) #endif { const REAL_PCRE *re = (const REAL_PCRE *)code; int entrysize; pcre_uchar *entry; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 char *first, *last; -#else +#elif defined COMPILE_PCRE16 PCRE_UCHAR16 *first, *last; +#elif defined COMPILE_PCRE32 +PCRE_UCHAR32 *first, *last; #endif -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0) return pcre_get_stringnumber(code, stringname); entrysize = pcre_get_stringtable_entries(code, stringname, &first, &last); -#else +#elif defined COMPILE_PCRE16 if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0) return pcre16_get_stringnumber(code, stringname); entrysize = pcre16_get_stringtable_entries(code, stringname, &first, &last); +#elif defined COMPILE_PCRE32 +if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0) + return pcre32_get_stringnumber(code, stringname); +entrysize = pcre32_get_stringtable_entries(code, stringname, &first, &last); #endif if (entrysize <= 0) return entrysize; for (entry = (pcre_uchar *)first; entry <= (pcre_uchar *)last; entry += entrysize) @@ -291,14 +330,18 @@ Returns: if successful: PCRE_ERROR_NOSUBSTRING (-7) no such captured substring */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int size) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_copy_substring(PCRE_SPTR16 subject, int *ovector, int stringcount, int stringnumber, PCRE_UCHAR16 *buffer, int size) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_copy_substring(PCRE_SPTR32 subject, int *ovector, int stringcount, + int stringnumber, PCRE_UCHAR32 *buffer, int size) #endif { int yield; @@ -342,24 +385,31 @@ Returns: if successful: PCRE_ERROR_NOSUBSTRING (-7) no such captured substring */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_copy_named_substring(const pcre *code, const char *subject, int *ovector, int stringcount, const char *stringname, char *buffer, int size) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_copy_named_substring(const pcre16 *code, PCRE_SPTR16 subject, int *ovector, int stringcount, PCRE_SPTR16 stringname, PCRE_UCHAR16 *buffer, int size) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_copy_named_substring(const pcre32 *code, PCRE_SPTR32 subject, + int *ovector, int stringcount, PCRE_SPTR32 stringname, + PCRE_UCHAR32 *buffer, int size) #endif { int n = get_first_set(code, stringname, ovector); if (n <= 0) return n; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size); -#else +#elif defined COMPILE_PCRE16 return pcre16_copy_substring(subject, ovector, stringcount, n, buffer, size); +#elif defined COMPILE_PCRE32 +return pcre32_copy_substring(subject, ovector, stringcount, n, buffer, size); #endif } @@ -386,14 +436,18 @@ Returns: if successful: 0 PCRE_ERROR_NOMEMORY (-6) failed to get store */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_substring_list(PCRE_SPTR16 subject, int *ovector, int stringcount, PCRE_SPTR16 **listptr) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_get_substring_list(PCRE_SPTR32 subject, int *ovector, int stringcount, + PCRE_SPTR32 **listptr) #endif { int i; @@ -408,10 +462,12 @@ for (i = 0; i < double_count; i += 2) stringlist = (pcre_uchar **)(PUBL(malloc))(size); if (stringlist == NULL) return PCRE_ERROR_NOMEMORY; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 *listptr = (const char **)stringlist; -#else +#elif defined COMPILE_PCRE16 *listptr = (PCRE_SPTR16 *)stringlist; +#elif defined COMPILE_PCRE32 +*listptr = (PCRE_SPTR32 *)stringlist; #endif p = (pcre_uchar *)(stringlist + stringcount + 1); @@ -442,12 +498,15 @@ Argument: the result of a previous pcre_get_substring_list() Returns: nothing */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre_free_substring_list(const char **pointer) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre16_free_substring_list(PCRE_SPTR16 *pointer) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN void PCRE_CALL_CONVENTION +pcre32_free_substring_list(PCRE_SPTR32 *pointer) #endif { (PUBL(free))((void *)pointer); @@ -480,14 +539,18 @@ Returns: if successful: PCRE_ERROR_NOSUBSTRING (-7) substring not present */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_substring(PCRE_SPTR16 subject, int *ovector, int stringcount, int stringnumber, PCRE_SPTR16 *stringptr) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_get_substring(PCRE_SPTR32 subject, int *ovector, int stringcount, + int stringnumber, PCRE_SPTR32 *stringptr) #endif { int yield; @@ -500,10 +563,12 @@ substring = (pcre_uchar *)(PUBL(malloc))(IN_UCHARS(yield + 1)); if (substring == NULL) return PCRE_ERROR_NOMEMORY; memcpy(substring, subject + ovector[stringnumber], IN_UCHARS(yield)); substring[yield] = 0; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 *stringptr = (const char *)substring; -#else +#elif defined COMPILE_PCRE16 *stringptr = (PCRE_SPTR16)substring; +#elif defined COMPILE_PCRE32 +*stringptr = (PCRE_SPTR32)substring; #endif return yield; } @@ -537,24 +602,31 @@ Returns: if successful: PCRE_ERROR_NOSUBSTRING (-7) no such captured substring */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_named_substring(const pcre *code, const char *subject, int *ovector, int stringcount, const char *stringname, const char **stringptr) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_named_substring(const pcre16 *code, PCRE_SPTR16 subject, int *ovector, int stringcount, PCRE_SPTR16 stringname, PCRE_SPTR16 *stringptr) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_get_named_substring(const pcre32 *code, PCRE_SPTR32 subject, + int *ovector, int stringcount, PCRE_SPTR32 stringname, + PCRE_SPTR32 *stringptr) #endif { int n = get_first_set(code, stringname, ovector); if (n <= 0) return n; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 return pcre_get_substring(subject, ovector, stringcount, n, stringptr); -#else +#elif defined COMPILE_PCRE16 return pcre16_get_substring(subject, ovector, stringcount, n, stringptr); +#elif defined COMPILE_PCRE32 +return pcre32_get_substring(subject, ovector, stringcount, n, stringptr); #endif } @@ -573,12 +645,15 @@ Argument: the result of a previous pcre_get_substring() Returns: nothing */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre_free_substring(const char *pointer) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre16_free_substring(PCRE_SPTR16 pointer) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN void PCRE_CALL_CONVENTION +pcre32_free_substring(PCRE_SPTR32 pointer) #endif { (PUBL(free))((void *)pointer); diff --git a/src/3rd/pcre/pcreinal.h b/src/3rd/pcre/pcreinal.h index b8f40ece85..0b9798c554 100644 --- a/src/3rd/pcre/pcreinal.h +++ b/src/3rd/pcre/pcreinal.h @@ -7,7 +7,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2012 University of Cambridge + Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -40,8 +40,8 @@ POSSIBILITY OF SUCH DAMAGE. /* This header contains definitions that are shared between the different modules, but which are not relevant to the exported API. This includes some -functions whose names all begin with "_pcre_" or "_pcre16_" depending on -the PRIV macro. */ +functions whose names all begin with "_pcre_", "_pcre16_" or "_pcre32_" +depending on the PRIV macro. */ #ifndef PCRE_INTERNAL_H #define PCRE_INTERNAL_H @@ -53,7 +53,8 @@ the PRIV macro. */ #endif /* PCRE is compiled as an 8 bit library if it is not requested otherwise. */ -#ifndef COMPILE_PCRE16 + +#if !defined COMPILE_PCRE16 && !defined COMPILE_PCRE32 #define COMPILE_PCRE8 #endif @@ -78,11 +79,11 @@ Until then we define it if SUPPORT_UTF is defined. */ #define SUPPORT_UTF8 1 #endif -/* We do not support both EBCDIC and UTF-8/16 at the same time. The "configure" +/* We do not support both EBCDIC and UTF-8/16/32 at the same time. The "configure" script prevents both being selected, but not everybody uses "configure". */ #if defined EBCDIC && defined SUPPORT_UTF -#error The use of both EBCDIC and SUPPORT_UTF8/16 is not supported. +#error The use of both EBCDIC and SUPPORT_UTF is not supported. #endif /* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef @@ -111,6 +112,12 @@ setjmp and stdarg are used is when NO_RECURSE is set. */ #include #include +/* Valgrind (memcheck) support */ + +#ifdef SUPPORT_VALGRIND +#include +#endif + /* When compiling a DLL for Windows, the exported symbols have to be declared using some MS magic. I found some useful information on this web page: http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the @@ -187,23 +194,31 @@ preprocessor time in standard C environments. */ typedef unsigned char pcre_uint8; #if USHRT_MAX == 65535 - typedef unsigned short pcre_uint16; - typedef short pcre_int16; +typedef unsigned short pcre_uint16; +typedef short pcre_int16; +#define PCRE_UINT16_MAX USHRT_MAX +#define PCRE_INT16_MAX SHRT_MAX #elif UINT_MAX == 65535 - typedef unsigned int pcre_uint16; - typedef int pcre_int16; +typedef unsigned int pcre_uint16; +typedef int pcre_int16; +#define PCRE_UINT16_MAX UINT_MAX +#define PCRE_INT16_MAX INT_MAX #else - #error Cannot determine a type for 16-bit unsigned integers +#error Cannot determine a type for 16-bit integers #endif -#if UINT_MAX == 4294967295 - typedef unsigned int pcre_uint32; - typedef int pcre_int32; -#elif ULONG_MAX == 4294967295 - typedef unsigned long int pcre_uint32; - typedef long int pcre_int32; +#if UINT_MAX == 4294967295U +typedef unsigned int pcre_uint32; +typedef int pcre_int32; +#define PCRE_UINT32_MAX UINT_MAX +#define PCRE_INT32_MAX INT_MAX +#elif ULONG_MAX == 4294967295UL +typedef unsigned long int pcre_uint32; +typedef long int pcre_int32; +#define PCRE_UINT32_MAX ULONG_MAX +#define PCRE_INT32_MAX LONG_MAX #else - #error Cannot determine a type for 32-bit unsigned integers +#error Cannot determine a type for 32-bit integers #endif /* When checking for integer overflow in pcre_compile(), we need to handle @@ -214,9 +229,9 @@ stdint.h is available, include it; it may define INT64_MAX. Systems that do not have stdint.h (e.g. Solaris) may have inttypes.h. The macro int64_t may be set by "configure". */ -#if HAVE_STDINT_H +#if defined HAVE_STDINT_H #include -#elif HAVE_INTTYPES_H +#elif defined HAVE_INTTYPES_H #include #endif @@ -243,16 +258,15 @@ exactly 256 items. When the character is able to contain more than 256 items, some check is needed before accessing these tables. */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 typedef unsigned char pcre_uchar; #define IN_UCHARS(x) (x) #define MAX_255(c) 1 #define TABLE_GET(c, table, default) ((table)[c]) -#else +#elif defined COMPILE_PCRE16 -#ifdef COMPILE_PCRE16 #if USHRT_MAX != 65535 /* This is a warning message. Change PCRE_UCHAR16 to a 16 bit data type in pcre.h(.in) and disable (comment out) this message. */ @@ -260,15 +274,22 @@ pcre.h(.in) and disable (comment out) this message. */ #endif typedef pcre_uint16 pcre_uchar; -#define IN_UCHARS(x) ((x) << 1) +#define UCHAR_SHIFT (1) +#define IN_UCHARS(x) ((x) << UCHAR_SHIFT) +#define MAX_255(c) ((c) <= 255u) +#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default)) + +#elif defined COMPILE_PCRE32 + +typedef pcre_uint32 pcre_uchar; +#define UCHAR_SHIFT (2) +#define IN_UCHARS(x) ((x) << UCHAR_SHIFT) #define MAX_255(c) ((c) <= 255u) #define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default)) #else #error Unsupported compiling mode -#endif /* COMPILE_PCRE16 */ - -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE[8|16|32] */ /* This is an unsigned int value that no character can ever have. UTF-8 characters only go up to 0x7fffffff (though Unicode doesn't go beyond @@ -295,8 +316,8 @@ start/end of string field names are. */ &(NLBLOCK->nllen), utf)) \ : \ ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \ - (p)[0] == NLBLOCK->nl[0] && \ - (NLBLOCK->nllen == 1 || (p)[1] == NLBLOCK->nl[1]) \ + RAWUCHARTEST(p) == NLBLOCK->nl[0] && \ + (NLBLOCK->nllen == 1 || RAWUCHARTEST(p+1) == NLBLOCK->nl[1]) \ ) \ ) @@ -309,8 +330,8 @@ start/end of string field names are. */ &(NLBLOCK->nllen), utf)) \ : \ ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \ - (p)[-NLBLOCK->nllen] == NLBLOCK->nl[0] && \ - (NLBLOCK->nllen == 1 || (p)[-NLBLOCK->nllen+1] == NLBLOCK->nl[1]) \ + RAWUCHARTEST(p - NLBLOCK->nllen) == NLBLOCK->nl[0] && \ + (NLBLOCK->nllen == 1 || RAWUCHARTEST(p - NLBLOCK->nllen + 1) == NLBLOCK->nl[1]) \ ) \ ) @@ -335,6 +356,11 @@ values. */ #include "pcre.h" #include "ucp.h" +#ifdef COMPILE_PCRE32 +/* Assert that the public PCRE_UCHAR32 is a 32-bit type */ +typedef int __assert_pcre_uchar32_size[sizeof(PCRE_UCHAR32) == 4 ? 1 : -1]; +#endif + /* When compiling for use with the Virtual Pascal compiler, these functions need to have their names changed. PCRE must be compiled with the -DVPCOMPAT option on the command line. */ @@ -396,7 +422,7 @@ The macros are controlled by the value of LINK_SIZE. This defaults to 2 in the config.h file, but can be overridden by using -D on the command line. This is automated on Unix systems via the "configure" command. */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 #if LINK_SIZE == 2 @@ -441,12 +467,11 @@ is automated on Unix systems via the "configure" command. */ #error LINK_SIZE must be either 2, 3, or 4 #endif -#else /* COMPILE_PCRE8 */ - -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 #if LINK_SIZE == 2 +/* Redefine LINK_SIZE as a multiple of sizeof(pcre_uchar) */ #undef LINK_SIZE #define LINK_SIZE 1 @@ -460,6 +485,7 @@ is automated on Unix systems via the "configure" command. */ #elif LINK_SIZE == 3 || LINK_SIZE == 4 +/* Redefine LINK_SIZE as a multiple of sizeof(pcre_uchar) */ #undef LINK_SIZE #define LINK_SIZE 2 @@ -477,11 +503,25 @@ is automated on Unix systems via the "configure" command. */ #error LINK_SIZE must be either 2, 3, or 4 #endif +#elif defined COMPILE_PCRE32 + +/* Only supported LINK_SIZE is 4 */ +/* Redefine LINK_SIZE as a multiple of sizeof(pcre_uchar) */ +#undef LINK_SIZE +#define LINK_SIZE 1 + +#define PUT(a,n,d) \ + (a[n] = (d)) + +#define GET(a,n) \ + (a[n]) + +/* Keep it positive */ +#define MAX_PATTERN_SIZE (1 << 30) + #else #error Unsupported compiling mode -#endif /* COMPILE_PCRE16 */ - -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE[8|16|32] */ /* Convenience macro defined in terms of the others */ @@ -492,7 +532,7 @@ is automated on Unix systems via the "configure" command. */ offsets changes. There are used for repeat counts and for other things such as capturing parenthesis numbers in back references. */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 #define IMM2_SIZE 2 @@ -500,12 +540,24 @@ capturing parenthesis numbers in back references. */ a[n] = (d) >> 8; \ a[(n)+1] = (d) & 255 +/* For reasons that I do not understand, the expression in this GET2 macro is +treated by gcc as a signed expression, even when a is declared as unsigned. It +seems that any kind of arithmetic results in a signed value. */ + #define GET2(a,n) \ - (((a)[n] << 8) | (a)[(n)+1]) + (unsigned int)(((a)[n] << 8) | (a)[(n)+1]) -#else /* COMPILE_PCRE8 */ +#elif defined COMPILE_PCRE16 -#ifdef COMPILE_PCRE16 +#define IMM2_SIZE 1 + +#define PUT2(a,n,d) \ + a[n] = d + +#define GET2(a,n) \ + a[n] + +#elif defined COMPILE_PCRE32 #define IMM2_SIZE 1 @@ -517,23 +569,25 @@ capturing parenthesis numbers in back references. */ #else #error Unsupported compiling mode -#endif /* COMPILE_PCRE16 */ - -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE[8|16|32] */ #define PUT2INC(a,n,d) PUT2(a,n,d), a += IMM2_SIZE /* The maximum length of a MARK name is currently one data unit; it may be changed in future to be a fixed number of bytes or to depend on LINK_SIZE. */ -#define MAX_MARK ((1 << (sizeof(pcre_uchar)*8)) - 1) +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 +#define MAX_MARK ((1u << 16) - 1) +#else +#define MAX_MARK ((1u << 8) - 1) +#endif /* When UTF encoding is being used, a character is no longer just a single -character. The macros for character handling generate simple sequences when -used in character-mode, and more complicated ones for UTF characters. -GETCHARLENTEST and other macros are not used when UTF is not supported, -so they are not defined. To make sure they can never even appear when -UTF support is omitted, we don't even define them. */ +byte. The macros for character handling generate simple sequences when used in +character-mode, and more complicated ones for UTF characters. GETCHARLENTEST +and other macros are not used when UTF is not supported, so they are not +defined. To make sure they can never even appear when UTF support is omitted, +we don't even define them. */ #ifndef SUPPORT_UTF @@ -546,6 +600,10 @@ UTF support is omitted, we don't even define them. */ #define GETCHARINC(c, eptr) c = *eptr++; #define GETCHARINCTEST(c, eptr) c = *eptr++; #define GETCHARLEN(c, eptr, len) c = *eptr; +#define RAWUCHAR(eptr) (*(eptr)) +#define RAWUCHARINC(eptr) (*(eptr)++) +#define RAWUCHARTEST(eptr) (*(eptr)) +#define RAWUCHARINCTEST(eptr) (*(eptr)++) /* #define GETCHARLENTEST(c, eptr, len) */ /* #define BACKCHAR(eptr) */ /* #define FORWARDCHAR(eptr) */ @@ -553,30 +611,9 @@ UTF support is omitted, we don't even define them. */ #else /* SUPPORT_UTF */ -#ifdef COMPILE_PCRE8 - -/* These macros were originally written in the form of loops that used data -from the tables whose names start with PRIV(utf8_table). They were rewritten by -a user so as not to use loops, because in some environments this gives a -significant performance advantage, and it seems never to do any harm. */ - -/* Tells the biggest code point which can be encoded as a single character. */ - -#define MAX_VALUE_FOR_SINGLE_CHAR 127 - /* Tests whether the code point needs extra characters to decode. */ -#define HAS_EXTRALEN(c) ((c) >= 0xc0) - -/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE. -Otherwise it has an undefined behaviour. */ - -#define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3f]) - -/* Returns TRUE, if the given character is not the first character -of a UTF sequence. */ - -#define NOT_FIRSTCHAR(c) (((c) & 0xc0) == 0x80) +#define HASUTF8EXTRALEN(c) ((c) >= 0xc0) /* Base macro to pick up the remaining bytes of a UTF-8 character, not advancing the pointer. */ @@ -600,20 +637,6 @@ advancing the pointer. */ ((eptr[4] & 0x3f) << 6) | (eptr[5] & 0x3f); \ } -/* Get the next UTF-8 character, not advancing the pointer. This is called when -we know we are in UTF-8 mode. */ - -#define GETCHAR(c, eptr) \ - c = *eptr; \ - if (c >= 0xc0) GETUTF8(c, eptr); - -/* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the -pointer. */ - -#define GETCHARTEST(c, eptr) \ - c = *eptr; \ - if (utf && c >= 0xc0) GETUTF8(c, eptr); - /* Base macro to pick up the remaining bytes of a UTF-8 character, advancing the pointer. */ @@ -648,6 +671,45 @@ the pointer. */ } \ } +#if defined COMPILE_PCRE8 + +/* These macros were originally written in the form of loops that used data +from the tables whose names start with PRIV(utf8_table). They were rewritten by +a user so as not to use loops, because in some environments this gives a +significant performance advantage, and it seems never to do any harm. */ + +/* Tells the biggest code point which can be encoded as a single character. */ + +#define MAX_VALUE_FOR_SINGLE_CHAR 127 + +/* Tests whether the code point needs extra characters to decode. */ + +#define HAS_EXTRALEN(c) ((c) >= 0xc0) + +/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE. +Otherwise it has an undefined behaviour. */ + +#define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3f]) + +/* Returns TRUE, if the given character is not the first character +of a UTF sequence. */ + +#define NOT_FIRSTCHAR(c) (((c) & 0xc0) == 0x80) + +/* Get the next UTF-8 character, not advancing the pointer. This is called when +we know we are in UTF-8 mode. */ + +#define GETCHAR(c, eptr) \ + c = *eptr; \ + if (c >= 0xc0) GETUTF8(c, eptr); + +/* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the +pointer. */ + +#define GETCHARTEST(c, eptr) \ + c = *eptr; \ + if (utf && c >= 0xc0) GETUTF8(c, eptr); + /* Get the next UTF-8 character, advancing the pointer. This is called when we know we are in UTF-8 mode. */ @@ -714,6 +776,30 @@ do not know if we are in UTF-8 mode. */ c = *eptr; \ if (utf && c >= 0xc0) GETUTF8LEN(c, eptr, len); +/* Returns the next uchar, not advancing the pointer. This is called when +we know we are in UTF mode. */ + +#define RAWUCHAR(eptr) \ + (*(eptr)) + +/* Returns the next uchar, advancing the pointer. This is called when +we know we are in UTF mode. */ + +#define RAWUCHARINC(eptr) \ + (*((eptr)++)) + +/* Returns the next uchar, testing for UTF mode, and not advancing the +pointer. */ + +#define RAWUCHARTEST(eptr) \ + (*(eptr)) + +/* Returns the next uchar, testing for UTF mode, advancing the +pointer. */ + +#define RAWUCHARINCTEST(eptr) \ + (*((eptr)++)) + /* If the pointer is not at the start of a character, move it back until it is. This is called only in UTF-8 mode - we don't put a test within the macro because almost all calls are already within a block of UTF-8 only code. */ @@ -727,9 +813,7 @@ because almost all calls are already within a block of UTF-8 only code. */ #define ACROSSCHAR(condition, eptr, action) \ while((condition) && ((eptr) & 0xc0) == 0x80) action -#else /* COMPILE_PCRE8 */ - -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 /* Tells the biggest code point which can be encoded as a single character. */ @@ -811,6 +895,30 @@ we do not know if we are in UTF-16 mode. */ c = *eptr; \ if (utf && (c & 0xfc00) == 0xd800) GETUTF16LEN(c, eptr, len); +/* Returns the next uchar, not advancing the pointer. This is called when +we know we are in UTF mode. */ + +#define RAWUCHAR(eptr) \ + (*(eptr)) + +/* Returns the next uchar, advancing the pointer. This is called when +we know we are in UTF mode. */ + +#define RAWUCHARINC(eptr) \ + (*((eptr)++)) + +/* Returns the next uchar, testing for UTF mode, and not advancing the +pointer. */ + +#define RAWUCHARTEST(eptr) \ + (*(eptr)) + +/* Returns the next uchar, testing for UTF mode, advancing the +pointer. */ + +#define RAWUCHARINCTEST(eptr) \ + (*((eptr)++)) + /* If the pointer is not at the start of a character, move it back until it is. This is called only in UTF-16 mode - we don't put a test within the macro because almost all calls are already within a block of UTF-16 only @@ -825,42 +933,232 @@ code. */ #define ACROSSCHAR(condition, eptr, action) \ if ((condition) && ((eptr) & 0xfc00) == 0xdc00) action -#endif +#elif defined COMPILE_PCRE32 -#endif /* COMPILE_PCRE8 */ +/* These are trivial for the 32-bit library, since all UTF-32 characters fit +into one pcre_uchar unit. */ +#define MAX_VALUE_FOR_SINGLE_CHAR (0x10ffffu) +#define HAS_EXTRALEN(c) (0) +#define GET_EXTRALEN(c) (0) +#define NOT_FIRSTCHAR(c) (0) + +/* Get the next UTF-32 character, not advancing the pointer. This is called when +we know we are in UTF-32 mode. */ + +#define GETCHAR(c, eptr) \ + c = *(eptr); + +/* Get the next UTF-32 character, testing for UTF-32 mode, and not advancing the +pointer. */ + +#define GETCHARTEST(c, eptr) \ + c = *(eptr); + +/* Get the next UTF-32 character, advancing the pointer. This is called when we +know we are in UTF-32 mode. */ + +#define GETCHARINC(c, eptr) \ + c = *((eptr)++); + +/* Get the next character, testing for UTF-32 mode, and advancing the pointer. +This is called when we don't know if we are in UTF-32 mode. */ + +#define GETCHARINCTEST(c, eptr) \ + c = *((eptr)++); + +/* Get the next UTF-32 character, not advancing the pointer, not incrementing +length (since all UTF-32 is of length 1). This is called when we know we are in +UTF-32 mode. */ + +#define GETCHARLEN(c, eptr, len) \ + GETCHAR(c, eptr) + +/* Get the next UTF-32character, testing for UTF-32 mode, not advancing the +pointer, not incrementing the length (since all UTF-32 is of length 1). +This is called when we do not know if we are in UTF-32 mode. */ + +#define GETCHARLENTEST(c, eptr, len) \ + GETCHARTEST(c, eptr) + +/* Returns the next uchar, not advancing the pointer. This is called when +we know we are in UTF mode. */ + +#define RAWUCHAR(eptr) \ + (*(eptr)) + +/* Returns the next uchar, advancing the pointer. This is called when +we know we are in UTF mode. */ + +#define RAWUCHARINC(eptr) \ + (*((eptr)++)) + +/* Returns the next uchar, testing for UTF mode, and not advancing the +pointer. */ + +#define RAWUCHARTEST(eptr) \ + (*(eptr)) + +/* Returns the next uchar, testing for UTF mode, advancing the +pointer. */ + +#define RAWUCHARINCTEST(eptr) \ + (*((eptr)++)) + +/* If the pointer is not at the start of a character, move it back until +it is. This is called only in UTF-32 mode - we don't put a test within the +macro because almost all calls are already within a block of UTF-32 only +code. +These are all no-ops since all UTF-32 characters fit into one pcre_uchar. */ + +#define BACKCHAR(eptr) do { } while (0) + +/* Same as above, just in the other direction. */ +#define FORWARDCHAR(eptr) do { } while (0) + +/* Same as above, but it allows a fully customizable form. */ +#define ACROSSCHAR(condition, eptr, action) do { } while (0) + +#else +#error Unsupported compiling mode +#endif /* COMPILE_PCRE[8|16|32] */ #endif /* SUPPORT_UTF */ +/* Tests for Unicode horizontal and vertical whitespace characters must check a +number of different values. Using a switch statement for this generates the +fastest code (no loop, no memory access), and there are several places in the +interpreter code where this happens. In order to ensure that all the case lists +remain in step, we use macros so that there is only one place where the lists +are defined. -/* In case there is no definition of offsetof() provided - though any proper -Standard C system should have one. */ +These values are also required as lists in pcre_compile.c when processing \h, +\H, \v and \V in a character class. The lists are defined in pcre_tables.c, but +macros that define the values are here so that all the definitions are +together. The lists must be in ascending character order, terminated by +NOTACHAR (which is 0xffffffff). -#ifndef offsetof -#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field)) +Any changes should ensure that the various macros are kept in step with each +other. NOTE: The values also appear in pcre_jit_compile.c. */ + +/* ------ ASCII/Unicode environments ------ */ + +#ifndef EBCDIC + +#define HSPACE_LIST \ + CHAR_HT, CHAR_SPACE, 0xa0, \ + 0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, \ + 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202f, 0x205f, 0x3000, \ + NOTACHAR + +#define HSPACE_MULTIBYTE_CASES \ + case 0x1680: /* OGHAM SPACE MARK */ \ + case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ \ + case 0x2000: /* EN QUAD */ \ + case 0x2001: /* EM QUAD */ \ + case 0x2002: /* EN SPACE */ \ + case 0x2003: /* EM SPACE */ \ + case 0x2004: /* THREE-PER-EM SPACE */ \ + case 0x2005: /* FOUR-PER-EM SPACE */ \ + case 0x2006: /* SIX-PER-EM SPACE */ \ + case 0x2007: /* FIGURE SPACE */ \ + case 0x2008: /* PUNCTUATION SPACE */ \ + case 0x2009: /* THIN SPACE */ \ + case 0x200A: /* HAIR SPACE */ \ + case 0x202f: /* NARROW NO-BREAK SPACE */ \ + case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ \ + case 0x3000 /* IDEOGRAPHIC SPACE */ + +#define HSPACE_BYTE_CASES \ + case CHAR_HT: \ + case CHAR_SPACE: \ + case 0xa0 /* NBSP */ + +#define HSPACE_CASES \ + HSPACE_BYTE_CASES: \ + HSPACE_MULTIBYTE_CASES + +#define VSPACE_LIST \ + CHAR_LF, CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, 0x2028, 0x2029, NOTACHAR + +#define VSPACE_MULTIBYTE_CASES \ + case 0x2028: /* LINE SEPARATOR */ \ + case 0x2029 /* PARAGRAPH SEPARATOR */ + +#define VSPACE_BYTE_CASES \ + case CHAR_LF: \ + case CHAR_VT: \ + case CHAR_FF: \ + case CHAR_CR: \ + case CHAR_NEL + +#define VSPACE_CASES \ + VSPACE_BYTE_CASES: \ + VSPACE_MULTIBYTE_CASES + +/* ------ EBCDIC environments ------ */ + +#else +#define HSPACE_LIST CHAR_HT, CHAR_SPACE + +#define HSPACE_BYTE_CASES \ + case CHAR_HT: \ + case CHAR_SPACE + +#define HSPACE_CASES HSPACE_BYTE_CASES + +#ifdef EBCDIC_NL25 +#define VSPACE_LIST \ + CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, CHAR_LF, NOTACHAR +#else +#define VSPACE_LIST \ + CHAR_VT, CHAR_FF, CHAR_CR, CHAR_LF, CHAR_NEL, NOTACHAR #endif +#define VSPACE_BYTE_CASES \ + case CHAR_LF: \ + case CHAR_VT: \ + case CHAR_FF: \ + case CHAR_CR: \ + case CHAR_NEL + +#define VSPACE_CASES VSPACE_BYTE_CASES +#endif /* EBCDIC */ + +/* ------ End of whitespace macros ------ */ + + /* Private flags containing information about the compiled regex. They used to -live at the top end of the options word, but that got almost full, so now they -are in a 16-bit flags word. From release 8.00, PCRE_NOPARTIAL is unused, as -the restrictions on partial matching have been lifted. It remains for backwards +live at the top end of the options word, but that got almost full, so they were +moved to a 16-bit flags word - which got almost full, so now they are in a +32-bit flags word. From release 8.00, PCRE_NOPARTIAL is unused, as the +restrictions on partial matching have been lifted. It remains for backwards compatibility. */ -#ifdef COMPILE_PCRE8 -#define PCRE_MODE 0x0001 /* compiled in 8 bit mode */ +#define PCRE_MODE8 0x00000001 /* compiled in 8 bit mode */ +#define PCRE_MODE16 0x00000002 /* compiled in 16 bit mode */ +#define PCRE_MODE32 0x00000004 /* compiled in 32 bit mode */ +#define PCRE_FIRSTSET 0x00000010 /* first_char is set */ +#define PCRE_FCH_CASELESS 0x00000020 /* caseless first char */ +#define PCRE_REQCHSET 0x00000040 /* req_byte is set */ +#define PCRE_RCH_CASELESS 0x00000080 /* caseless requested char */ +#define PCRE_STARTLINE 0x00000100 /* start after \n for multiline */ +#define PCRE_NOPARTIAL 0x00000200 /* can't use partial with this regex */ +#define PCRE_JCHANGED 0x00000400 /* j option used in regex */ +#define PCRE_HASCRORLF 0x00000800 /* explicit \r or \n in pattern */ +#define PCRE_HASTHEN 0x00001000 /* pattern contains (*THEN) */ +#define PCRE_MLSET 0x00002000 /* match limit set by regex */ +#define PCRE_RLSET 0x00004000 /* recursion limit set by regex */ +#define PCRE_MATCH_EMPTY 0x00008000 /* pattern can match empty string */ + +#if defined COMPILE_PCRE8 +#define PCRE_MODE PCRE_MODE8 +#elif defined COMPILE_PCRE16 +#define PCRE_MODE PCRE_MODE16 +#elif defined COMPILE_PCRE32 +#define PCRE_MODE PCRE_MODE32 #endif -#ifdef COMPILE_PCRE16 -#define PCRE_MODE 0x0002 /* compiled in 16 bit mode */ -#endif -#define PCRE_FIRSTSET 0x0010 /* first_char is set */ -#define PCRE_FCH_CASELESS 0x0020 /* caseless first char */ -#define PCRE_REQCHSET 0x0040 /* req_byte is set */ -#define PCRE_RCH_CASELESS 0x0080 /* caseless requested char */ -#define PCRE_STARTLINE 0x0100 /* start after \n for multiline */ -#define PCRE_NOPARTIAL 0x0200 /* can't use partial with this regex */ -#define PCRE_JCHANGED 0x0400 /* j option used in regex */ -#define PCRE_HASCRORLF 0x0800 /* explicit \r or \n in pattern */ -#define PCRE_HASTHEN 0x1000 /* pattern contains (*THEN) */ +#define PCRE_MODE_MASK (PCRE_MODE8 | PCRE_MODE16 | PCRE_MODE32) /* Flags for the "extra" block produced by pcre_study(). */ @@ -876,9 +1174,10 @@ time, run time, or study time, respectively. */ #define PUBLIC_COMPILE_OPTIONS \ (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \ - PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE| \ + PCRE_NO_AUTO_CAPTURE|PCRE_NO_AUTO_POSSESS| \ + PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE| \ PCRE_DUPNAMES|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE| \ - PCRE_JAVASCRIPT_COMPAT|PCRE_UCP|PCRE_NO_START_OPTIMIZE) + PCRE_JAVASCRIPT_COMPAT|PCRE_UCP|PCRE_NO_START_OPTIMIZE|PCRE_NEVER_UTF) #define PUBLIC_EXEC_OPTIONS \ (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NOTEMPTY_ATSTART| \ @@ -893,7 +1192,11 @@ time, run time, or study time, respectively. */ #define PUBLIC_STUDY_OPTIONS \ (PCRE_STUDY_JIT_COMPILE|PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE| \ - PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE) + PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE|PCRE_STUDY_EXTRA_NEEDED) + +#define PUBLIC_JIT_EXEC_OPTIONS \ + (PCRE_NO_UTF8_CHECK|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|\ + PCRE_NOTEMPTY_ATSTART|PCRE_PARTIAL_SOFT|PCRE_PARTIAL_HARD) /* Magic number to provide a small check against being handed junk. */ @@ -904,11 +1207,6 @@ in different endianness. */ #define REVERSED_MAGIC_NUMBER 0x45524350UL /* 'ERCP' */ -/* Negative values for the firstchar and reqchar variables */ - -#define REQ_UNSET (-2) -#define REQ_NONE (-1) - /* The maximum remaining length of subject we are prepared to search for a req_byte match. */ @@ -945,22 +1243,71 @@ macros to give the functions distinct names. */ #ifndef SUPPORT_UTF /* UTF-8 support is not enabled; use the platform-dependent character literals -so that PCRE works on both ASCII and EBCDIC platforms, in non-UTF-mode only. */ +so that PCRE works in both ASCII and EBCDIC environments, but only in non-UTF +mode. Newline characters are problematic in EBCDIC. Though it has CR and LF +characters, a common practice has been to use its NL (0x15) character as the +line terminator in C-like processing environments. However, sometimes the LF +(0x25) character is used instead, according to this Unicode document: +http://unicode.org/standard/reports/tr13/tr13-5.html + +PCRE defaults EBCDIC NL to 0x15, but has a build-time option to select 0x25 +instead. Whichever is *not* chosen is defined as NEL. + +In both ASCII and EBCDIC environments, CHAR_NL and CHAR_LF are synonyms for the +same code point. */ + +#ifdef EBCDIC + +#ifndef EBCDIC_NL25 +#define CHAR_NL '\x15' +#define CHAR_NEL '\x25' +#define STR_NL "\x15" +#define STR_NEL "\x25" +#else +#define CHAR_NL '\x25' +#define CHAR_NEL '\x15' +#define STR_NL "\x25" +#define STR_NEL "\x15" +#endif + +#define CHAR_LF CHAR_NL +#define STR_LF STR_NL + +#define CHAR_ESC '\047' +#define CHAR_DEL '\007' +#define STR_ESC "\047" +#define STR_DEL "\007" + +#else /* Not EBCDIC */ + +/* In ASCII/Unicode, linefeed is '\n' and we equate this to NL for +compatibility. NEL is the Unicode newline character; make sure it is +a positive value. */ + +#define CHAR_LF '\n' +#define CHAR_NL CHAR_LF +#define CHAR_NEL ((unsigned char)'\x85') +#define CHAR_ESC '\033' +#define CHAR_DEL '\177' + +#define STR_LF "\n" +#define STR_NL STR_LF +#define STR_NEL "\x85" +#define STR_ESC "\033" +#define STR_DEL "\177" + +#endif /* EBCDIC */ + +/* The remaining definitions work in both environments. */ + +#define CHAR_NULL '\0' #define CHAR_HT '\t' #define CHAR_VT '\v' #define CHAR_FF '\f' #define CHAR_CR '\r' -#define CHAR_NL '\n' #define CHAR_BS '\b' #define CHAR_BEL '\a' -#ifdef EBCDIC -#define CHAR_ESC '\047' -#define CHAR_DEL '\007' -#else -#define CHAR_ESC '\033' -#define CHAR_DEL '\177' -#endif #define CHAR_SPACE ' ' #define CHAR_EXCLAMATION_MARK '!' @@ -1062,16 +1409,8 @@ so that PCRE works on both ASCII and EBCDIC platforms, in non-UTF-mode only. */ #define STR_VT "\v" #define STR_FF "\f" #define STR_CR "\r" -#define STR_NL "\n" #define STR_BS "\b" #define STR_BEL "\a" -#ifdef EBCDIC -#define STR_ESC "\047" -#define STR_DEL "\007" -#else -#define STR_ESC "\033" -#define STR_DEL "\177" -#endif #define STR_SPACE " " #define STR_EXCLAMATION_MARK "!" @@ -1194,22 +1533,25 @@ so that PCRE works on both ASCII and EBCDIC platforms, in non-UTF-mode only. */ #define STRING_xdigit "xdigit" #define STRING_DEFINE "DEFINE" +#define STRING_WEIRD_STARTWORD "[:<:]]" +#define STRING_WEIRD_ENDWORD "[:>:]]" -#define STRING_CR_RIGHTPAR "CR)" -#define STRING_LF_RIGHTPAR "LF)" -#define STRING_CRLF_RIGHTPAR "CRLF)" -#define STRING_ANY_RIGHTPAR "ANY)" -#define STRING_ANYCRLF_RIGHTPAR "ANYCRLF)" -#define STRING_BSR_ANYCRLF_RIGHTPAR "BSR_ANYCRLF)" -#define STRING_BSR_UNICODE_RIGHTPAR "BSR_UNICODE)" -#ifdef COMPILE_PCRE8 -#define STRING_UTF_RIGHTPAR "UTF8)" -#endif -#ifdef COMPILE_PCRE16 -#define STRING_UTF_RIGHTPAR "UTF16)" -#endif -#define STRING_UCP_RIGHTPAR "UCP)" -#define STRING_NO_START_OPT_RIGHTPAR "NO_START_OPT)" +#define STRING_CR_RIGHTPAR "CR)" +#define STRING_LF_RIGHTPAR "LF)" +#define STRING_CRLF_RIGHTPAR "CRLF)" +#define STRING_ANY_RIGHTPAR "ANY)" +#define STRING_ANYCRLF_RIGHTPAR "ANYCRLF)" +#define STRING_BSR_ANYCRLF_RIGHTPAR "BSR_ANYCRLF)" +#define STRING_BSR_UNICODE_RIGHTPAR "BSR_UNICODE)" +#define STRING_UTF8_RIGHTPAR "UTF8)" +#define STRING_UTF16_RIGHTPAR "UTF16)" +#define STRING_UTF32_RIGHTPAR "UTF32)" +#define STRING_UTF_RIGHTPAR "UTF)" +#define STRING_UCP_RIGHTPAR "UCP)" +#define STRING_NO_AUTO_POSSESS_RIGHTPAR "NO_AUTO_POSSESS)" +#define STRING_NO_START_OPT_RIGHTPAR "NO_START_OPT)" +#define STRING_LIMIT_MATCH_EQ "LIMIT_MATCH=" +#define STRING_LIMIT_RECURSION_EQ "LIMIT_RECURSION=" #else /* SUPPORT_UTF */ @@ -1221,12 +1563,15 @@ only. */ #define CHAR_VT '\013' #define CHAR_FF '\014' #define CHAR_CR '\015' -#define CHAR_NL '\012' +#define CHAR_LF '\012' +#define CHAR_NL CHAR_LF +#define CHAR_NEL ((unsigned char)'\x85') #define CHAR_BS '\010' #define CHAR_BEL '\007' #define CHAR_ESC '\033' #define CHAR_DEL '\177' +#define CHAR_NULL '\0' #define CHAR_SPACE '\040' #define CHAR_EXCLAMATION_MARK '\041' #define CHAR_QUOTATION_MARK '\042' @@ -1454,22 +1799,25 @@ only. */ #define STRING_xdigit STR_x STR_d STR_i STR_g STR_i STR_t #define STRING_DEFINE STR_D STR_E STR_F STR_I STR_N STR_E +#define STRING_WEIRD_STARTWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_LESS_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET +#define STRING_WEIRD_ENDWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_GREATER_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET -#define STRING_CR_RIGHTPAR STR_C STR_R STR_RIGHT_PARENTHESIS -#define STRING_LF_RIGHTPAR STR_L STR_F STR_RIGHT_PARENTHESIS -#define STRING_CRLF_RIGHTPAR STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS -#define STRING_ANY_RIGHTPAR STR_A STR_N STR_Y STR_RIGHT_PARENTHESIS -#define STRING_ANYCRLF_RIGHTPAR STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS -#define STRING_BSR_ANYCRLF_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS -#define STRING_BSR_UNICODE_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS -#ifdef COMPILE_PCRE8 -#define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_8 STR_RIGHT_PARENTHESIS -#endif -#ifdef COMPILE_PCRE16 -#define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_1 STR_6 STR_RIGHT_PARENTHESIS -#endif -#define STRING_UCP_RIGHTPAR STR_U STR_C STR_P STR_RIGHT_PARENTHESIS -#define STRING_NO_START_OPT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_S STR_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS +#define STRING_CR_RIGHTPAR STR_C STR_R STR_RIGHT_PARENTHESIS +#define STRING_LF_RIGHTPAR STR_L STR_F STR_RIGHT_PARENTHESIS +#define STRING_CRLF_RIGHTPAR STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS +#define STRING_ANY_RIGHTPAR STR_A STR_N STR_Y STR_RIGHT_PARENTHESIS +#define STRING_ANYCRLF_RIGHTPAR STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS +#define STRING_BSR_ANYCRLF_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS +#define STRING_BSR_UNICODE_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS +#define STRING_UTF8_RIGHTPAR STR_U STR_T STR_F STR_8 STR_RIGHT_PARENTHESIS +#define STRING_UTF16_RIGHTPAR STR_U STR_T STR_F STR_1 STR_6 STR_RIGHT_PARENTHESIS +#define STRING_UTF32_RIGHTPAR STR_U STR_T STR_F STR_3 STR_2 STR_RIGHT_PARENTHESIS +#define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_RIGHT_PARENTHESIS +#define STRING_UCP_RIGHTPAR STR_U STR_C STR_P STR_RIGHT_PARENTHESIS +#define STRING_NO_AUTO_POSSESS_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_A STR_U STR_T STR_O STR_UNDERSCORE STR_P STR_O STR_S STR_S STR_E STR_S STR_S STR_RIGHT_PARENTHESIS +#define STRING_NO_START_OPT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_S STR_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS +#define STRING_LIMIT_MATCH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_M STR_A STR_T STR_C STR_H STR_EQUALS_SIGN +#define STRING_LIMIT_RECURSION_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_R STR_E STR_C STR_U STR_R STR_S STR_I STR_O STR_N STR_EQUALS_SIGN #endif /* SUPPORT_UTF */ @@ -1484,7 +1832,7 @@ only. */ #endif #ifndef ESC_n -#define ESC_n CHAR_NL +#define ESC_n CHAR_LF #endif #ifndef ESC_r @@ -1509,6 +1857,19 @@ only. */ #define PT_SPACE 6 /* Perl space - Z plus 9,10,12,13 */ #define PT_PXSPACE 7 /* POSIX space - Z plus 9,10,11,12,13 */ #define PT_WORD 8 /* Word - L plus N plus underscore */ +#define PT_CLIST 9 /* Pseudo-property: match character list */ +#define PT_UCNC 10 /* Universal Character nameable character */ +#define PT_TABSIZE 11 /* Size of square table for autopossessify tests */ + +/* The following special properties are used only in XCLASS items, when POSIX +classes are specified and PCRE_UCP is set - in other words, for Unicode +handling of these classes. They are not available via the \p or \P escapes like +those in the above list, and so they do not take part in the autopossessifying +table. */ + +#define PT_PXGRAPH 11 /* [:graph:] - characters that mark the paper */ +#define PT_PXPRINT 12 /* [:print:] - [:graph:] plus non-control spaces */ +#define PT_PXPUNCT 13 /* [:punct:] - punctuation characters */ /* Flag bits and data types for the extended class (OP_XCLASS) for classes that contain characters with values greater than 255. */ @@ -1523,20 +1884,20 @@ contain characters with values greater than 255. */ #define XCL_NOTPROP 4 /* Unicode inverted property (ditto) */ /* These are escaped items that aren't just an encoding of a particular data -value such as \n. They must have non-zero values, as check_escape() returns -their negation. Also, they must appear in the same order as in the opcode -definitions below, up to ESC_z. There's a dummy for OP_ALLANY because it +value such as \n. They must have non-zero values, as check_escape() returns 0 +for a data character. Also, they must appear in the same order as in the +opcode definitions below, up to ESC_z. There's a dummy for OP_ALLANY because it corresponds to "." in DOTALL mode rather than an escape sequence. It is also used for [^] in JavaScript compatibility mode, and for \C in non-utf mode. In non-DOTALL mode, "." behaves like \N. The special values ESC_DU, ESC_du, etc. are used instead of ESC_D, ESC_d, etc. -when PCRE_UCP is set, when replacement of \d etc by \p sequences is required. +when PCRE_UCP is set and replacement of \d etc by \p sequences is required. They must be contiguous, and remain in order so that the replacements can be looked up from a table. -The final escape must be ESC_REF as subsequent values are used for -backreferences (\1, \2, \3, etc). There are two tests in the code for an escape +Negative numbers are used to encode a backreference (\1, \2, \3, etc.) in +check_escape(). There are two tests in the code for an escape greater than ESC_b and less than ESC_Z to detect the types that may be repeated. These are the types that consume characters. If any new escapes are put in between that don't consume a character, that code will have to change. @@ -1546,15 +1907,33 @@ enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H, ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z, ESC_E, ESC_Q, ESC_g, ESC_k, - ESC_DU, ESC_du, ESC_SU, ESC_su, ESC_WU, ESC_wu, - ESC_REF }; + ESC_DU, ESC_du, ESC_SU, ESC_su, ESC_WU, ESC_wu }; -/* Opcode table: Starting from 1 (i.e. after OP_END), the values up to -OP_EOD must correspond in order to the list of escapes immediately above. -*** NOTE NOTE NOTE *** Whenever this list is updated, the two macro definitions -that follow must also be updated to match. There are also tables called -"coptable" and "poptable" in pcre_dfa_exec.c that must be updated. */ +/********************** Opcode definitions ******************/ + +/****** NOTE NOTE NOTE ****** + +Starting from 1 (i.e. after OP_END), the values up to OP_EOD must correspond in +order to the list of escapes immediately above. Furthermore, values up to +OP_DOLLM must not be changed without adjusting the table called autoposstab in +pcre_compile.c + +Whenever this list is updated, the two macro definitions that follow must be +updated to match. The possessification table called "opcode_possessify" in +pcre_compile.c must also be updated, and also the tables called "coptable" +and "poptable" in pcre_dfa_exec.c. + +****** NOTE NOTE NOTE ******/ + + +/* The values between FIRST_AUTOTAB_OP and LAST_AUTOTAB_RIGHT_OP, inclusive, +are used in a table for deciding whether a repeated character type can be +auto-possessified. */ + +#define FIRST_AUTOTAB_OP OP_NOT_DIGIT +#define LAST_AUTOTAB_LEFT_OP OP_EXTUNI +#define LAST_AUTOTAB_RIGHT_OP OP_DOLLM enum { OP_END, /* 0 End of pattern */ @@ -1573,7 +1952,7 @@ enum { OP_NOT_WORDCHAR, /* 10 \W */ OP_WORDCHAR, /* 11 \w */ - OP_ANY, /* 12 Match any character except newline */ + OP_ANY, /* 12 Match any character except newline (\N) */ OP_ALLANY, /* 13 Match any character */ OP_ANYBYTE, /* 14 Match any byte (\C); different to OP_ANY for UTF-8 */ OP_NOTPROP, /* 15 \P (not Unicode property) */ @@ -1584,13 +1963,18 @@ enum { OP_NOT_VSPACE, /* 20 \V (not vertical whitespace) */ OP_VSPACE, /* 21 \v (vertical whitespace) */ OP_EXTUNI, /* 22 \X (extended Unicode sequence */ - OP_EODN, /* 23 End of data or \n at end of data: \Z. */ - OP_EOD, /* 24 End of data: \z */ + OP_EODN, /* 23 End of data or \n at end of data (\Z) */ + OP_EOD, /* 24 End of data (\z) */ + + /* Line end assertions */ + + OP_DOLL, /* 25 End of line - not multiline */ + OP_DOLLM, /* 26 End of line - multiline */ + OP_CIRC, /* 27 Start of line - not multiline */ + OP_CIRCM, /* 28 Start of line - multiline */ + + /* Single characters; caseful must precede the caseless ones */ - OP_CIRC, /* 25 Start of line - not multiline */ - OP_CIRCM, /* 26 Start of line - multiline */ - OP_DOLL, /* 27 End of line - not multiline */ - OP_DOLLM, /* 28 End of line - multiline */ OP_CHAR, /* 29 Match one character, casefully */ OP_CHARI, /* 30 Match one character, caselessly */ OP_NOT, /* 31 Match one character, not the given one, casefully */ @@ -1599,7 +1983,7 @@ enum { /* The following sets of 13 opcodes must always be kept in step because the offset from the first one is used to generate the others. */ - /**** Single characters, caseful, must precede the caseless ones ****/ + /* Repeated characters; caseful must precede the caseless ones */ OP_STAR, /* 33 The maximizing and minimizing versions of */ OP_MINSTAR, /* 34 these six opcodes must come in pairs, with */ @@ -1617,7 +2001,7 @@ enum { OP_POSQUERY, /* 44 Posesssified query, caseful */ OP_POSUPTO, /* 45 Possessified upto, caseful */ - /**** Single characters, caseless, must follow the caseful ones */ + /* Repeated characters; caseless must follow the caseful ones */ OP_STARI, /* 46 */ OP_MINSTARI, /* 47 */ @@ -1635,8 +2019,8 @@ enum { OP_POSQUERYI, /* 57 Posesssified query, caseless */ OP_POSUPTOI, /* 58 Possessified upto, caseless */ - /**** The negated ones must follow the non-negated ones, and match them ****/ - /**** Negated single character, caseful; must precede the caseless ones ****/ + /* The negated ones must follow the non-negated ones, and match them */ + /* Negated repeated character, caseful; must precede the caseless ones */ OP_NOTSTAR, /* 59 The maximizing and minimizing versions of */ OP_NOTMINSTAR, /* 60 these six opcodes must come in pairs, with */ @@ -1654,7 +2038,7 @@ enum { OP_NOTPOSQUERY, /* 70 */ OP_NOTPOSUPTO, /* 71 */ - /**** Negated single character, caseless; must follow the caseful ones ****/ + /* Negated repeated character, caseless; must follow the caseful ones */ OP_NOTSTARI, /* 72 */ OP_NOTMINSTARI, /* 73 */ @@ -1672,7 +2056,7 @@ enum { OP_NOTPOSQUERYI, /* 83 */ OP_NOTPOSUPTOI, /* 84 */ - /**** Character types ****/ + /* Character types */ OP_TYPESTAR, /* 85 The maximizing and minimizing versions of */ OP_TYPEMINSTAR, /* 86 these six opcodes must come in pairs, with */ @@ -1703,89 +2087,96 @@ enum { OP_CRRANGE, /* 104 These are different to the three sets above. */ OP_CRMINRANGE, /* 105 */ + OP_CRPOSSTAR, /* 106 Possessified versions */ + OP_CRPOSPLUS, /* 107 */ + OP_CRPOSQUERY, /* 108 */ + OP_CRPOSRANGE, /* 109 */ + /* End of quantifier opcodes */ - OP_CLASS, /* 106 Match a character class, chars < 256 only */ - OP_NCLASS, /* 107 Same, but the bitmap was created from a negative + OP_CLASS, /* 110 Match a character class, chars < 256 only */ + OP_NCLASS, /* 111 Same, but the bitmap was created from a negative class - the difference is relevant only when a character > 255 is encountered. */ - OP_XCLASS, /* 108 Extended class for handling > 255 chars within the + OP_XCLASS, /* 112 Extended class for handling > 255 chars within the class. This does both positive and negative. */ - OP_REF, /* 109 Match a back reference, casefully */ - OP_REFI, /* 110 Match a back reference, caselessly */ - OP_RECURSE, /* 111 Match a numbered subpattern (possibly recursive) */ - OP_CALLOUT, /* 112 Call out to external function if provided */ + OP_REF, /* 113 Match a back reference, casefully */ + OP_REFI, /* 114 Match a back reference, caselessly */ + OP_DNREF, /* 115 Match a duplicate name backref, casefully */ + OP_DNREFI, /* 116 Match a duplicate name backref, caselessly */ + OP_RECURSE, /* 117 Match a numbered subpattern (possibly recursive) */ + OP_CALLOUT, /* 118 Call out to external function if provided */ - OP_ALT, /* 113 Start of alternation */ - OP_KET, /* 114 End of group that doesn't have an unbounded repeat */ - OP_KETRMAX, /* 115 These two must remain together and in this */ - OP_KETRMIN, /* 116 order. They are for groups the repeat for ever. */ - OP_KETRPOS, /* 117 Possessive unlimited repeat. */ + OP_ALT, /* 119 Start of alternation */ + OP_KET, /* 120 End of group that doesn't have an unbounded repeat */ + OP_KETRMAX, /* 121 These two must remain together and in this */ + OP_KETRMIN, /* 122 order. They are for groups the repeat for ever. */ + OP_KETRPOS, /* 123 Possessive unlimited repeat. */ /* The assertions must come before BRA, CBRA, ONCE, and COND, and the four asserts must remain in order. */ - OP_REVERSE, /* 118 Move pointer back - used in lookbehind assertions */ - OP_ASSERT, /* 119 Positive lookahead */ - OP_ASSERT_NOT, /* 120 Negative lookahead */ - OP_ASSERTBACK, /* 121 Positive lookbehind */ - OP_ASSERTBACK_NOT, /* 122 Negative lookbehind */ + OP_REVERSE, /* 124 Move pointer back - used in lookbehind assertions */ + OP_ASSERT, /* 125 Positive lookahead */ + OP_ASSERT_NOT, /* 126 Negative lookahead */ + OP_ASSERTBACK, /* 127 Positive lookbehind */ + OP_ASSERTBACK_NOT, /* 128 Negative lookbehind */ /* ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come immediately after the assertions, with ONCE first, as there's a test for >= ONCE for a subpattern that isn't an assertion. The POS versions must immediately follow the non-POS versions in each case. */ - OP_ONCE, /* 123 Atomic group, contains captures */ - OP_ONCE_NC, /* 124 Atomic group containing no captures */ - OP_BRA, /* 125 Start of non-capturing bracket */ - OP_BRAPOS, /* 126 Ditto, with unlimited, possessive repeat */ - OP_CBRA, /* 127 Start of capturing bracket */ - OP_CBRAPOS, /* 128 Ditto, with unlimited, possessive repeat */ - OP_COND, /* 129 Conditional group */ + OP_ONCE, /* 129 Atomic group, contains captures */ + OP_ONCE_NC, /* 130 Atomic group containing no captures */ + OP_BRA, /* 131 Start of non-capturing bracket */ + OP_BRAPOS, /* 132 Ditto, with unlimited, possessive repeat */ + OP_CBRA, /* 133 Start of capturing bracket */ + OP_CBRAPOS, /* 134 Ditto, with unlimited, possessive repeat */ + OP_COND, /* 135 Conditional group */ /* These five must follow the previous five, in the same order. There's a check for >= SBRA to distinguish the two sets. */ - OP_SBRA, /* 130 Start of non-capturing bracket, check empty */ - OP_SBRAPOS, /* 131 Ditto, with unlimited, possessive repeat */ - OP_SCBRA, /* 132 Start of capturing bracket, check empty */ - OP_SCBRAPOS, /* 133 Ditto, with unlimited, possessive repeat */ - OP_SCOND, /* 134 Conditional group, check empty */ + OP_SBRA, /* 136 Start of non-capturing bracket, check empty */ + OP_SBRAPOS, /* 137 Ditto, with unlimited, possessive repeat */ + OP_SCBRA, /* 138 Start of capturing bracket, check empty */ + OP_SCBRAPOS, /* 139 Ditto, with unlimited, possessive repeat */ + OP_SCOND, /* 140 Conditional group, check empty */ /* The next two pairs must (respectively) be kept together. */ - OP_CREF, /* 135 Used to hold a capture number as condition */ - OP_NCREF, /* 136 Same, but generated by a name reference*/ - OP_RREF, /* 137 Used to hold a recursion number as condition */ - OP_NRREF, /* 138 Same, but generated by a name reference*/ - OP_DEF, /* 139 The DEFINE condition */ + OP_CREF, /* 141 Used to hold a capture number as condition */ + OP_DNCREF, /* 142 Used to point to duplicate names as a condition */ + OP_RREF, /* 143 Used to hold a recursion number as condition */ + OP_DNRREF, /* 144 Used to point to duplicate names as a condition */ + OP_DEF, /* 145 The DEFINE condition */ - OP_BRAZERO, /* 140 These two must remain together and in this */ - OP_BRAMINZERO, /* 141 order. */ - OP_BRAPOSZERO, /* 142 */ + OP_BRAZERO, /* 146 These two must remain together and in this */ + OP_BRAMINZERO, /* 147 order. */ + OP_BRAPOSZERO, /* 148 */ /* These are backtracking control verbs */ - OP_MARK, /* 143 always has an argument */ - OP_PRUNE, /* 144 */ - OP_PRUNE_ARG, /* 145 same, but with argument */ - OP_SKIP, /* 146 */ - OP_SKIP_ARG, /* 147 same, but with argument */ - OP_THEN, /* 148 */ - OP_THEN_ARG, /* 149 same, but with argument */ - OP_COMMIT, /* 150 */ + OP_MARK, /* 149 always has an argument */ + OP_PRUNE, /* 150 */ + OP_PRUNE_ARG, /* 151 same, but with argument */ + OP_SKIP, /* 152 */ + OP_SKIP_ARG, /* 153 same, but with argument */ + OP_THEN, /* 154 */ + OP_THEN_ARG, /* 155 same, but with argument */ + OP_COMMIT, /* 156 */ /* These are forced failure and success verbs */ - OP_FAIL, /* 151 */ - OP_ACCEPT, /* 152 */ - OP_ASSERT_ACCEPT, /* 153 Used inside assertions */ - OP_CLOSE, /* 154 Used before OP_ACCEPT to close open captures */ + OP_FAIL, /* 157 */ + OP_ACCEPT, /* 158 */ + OP_ASSERT_ACCEPT, /* 159 Used inside assertions */ + OP_CLOSE, /* 160 Used before OP_ACCEPT to close open captures */ /* This is used to skip a subpattern with a {0} quantifier */ - OP_SKIPZERO, /* 155 */ + OP_SKIPZERO, /* 161 */ /* This is not an opcode, but is used to check that tables indexed by opcode are the correct length, in order to catch updating errors - there have been @@ -1796,7 +2187,8 @@ enum { /* *** NOTE NOTE NOTE *** Whenever the list above is updated, the two macro definitions that follow must also be updated to match. There are also tables -called "coptable" and "poptable" in pcre_dfa_exec.c that must be updated. */ +called "opcode_possessify" in pcre_compile.c and "coptable" and "poptable" in +pcre_dfa_exec.c that must be updated. */ /* This macro defines textual names for all the opcodes. These are used only @@ -1809,7 +2201,7 @@ some cases doesn't actually use these names at all). */ "\\S", "\\s", "\\W", "\\w", "Any", "AllAny", "Anybyte", \ "notprop", "prop", "\\R", "\\H", "\\h", "\\V", "\\v", \ "extuni", "\\Z", "\\z", \ - "^", "^", "$", "$", "char", "chari", "not", "noti", \ + "$", "$", "^", "^", "char", "chari", "not", "noti", \ "*", "*?", "+", "+?", "?", "??", \ "{", "{", "{", \ "*+","++", "?+", "{", \ @@ -1825,7 +2217,8 @@ some cases doesn't actually use these names at all). */ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ "*+","++", "?+", "{", \ "*", "*?", "+", "+?", "?", "??", "{", "{", \ - "class", "nclass", "xclass", "Ref", "Refi", \ + "*+","++", "?+", "{", \ + "class", "nclass", "xclass", "Ref", "Refi", "DnRef", "DnRefi", \ "Recurse", "Callout", \ "Alt", "Ket", "KetRmax", "KetRmin", "KetRpos", \ "Reverse", "Assert", "Assert not", "AssertB", "AssertB not", \ @@ -1834,7 +2227,7 @@ some cases doesn't actually use these names at all). */ "Cond", \ "SBra", "SBraPos", "SCBra", "SCBraPos", \ "SCond", \ - "Cond ref", "Cond nref", "Cond rec", "Cond nrec", "Cond def", \ + "Cond ref", "Cond dnref", "Cond rec", "Cond dnrec", "Cond def", \ "Brazero", "Braminzero", "Braposzero", \ "*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP", \ "*THEN", "*THEN", "*COMMIT", "*FAIL", \ @@ -1859,7 +2252,7 @@ in UTF-8 mode. The code that uses this table must know about such things. */ 3, 3, /* \P, \p */ \ 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ \ 1, /* \X */ \ - 1, 1, 1, 1, 1, 1, /* \Z, \z, ^, ^M, $, $M */ \ + 1, 1, 1, 1, 1, 1, /* \Z, \z, $, $M ^, ^M */ \ 2, /* Char - the minimum length */ \ 2, /* Chari - the minimum length */ \ 2, /* not */ \ @@ -1890,11 +2283,14 @@ in UTF-8 mode. The code that uses this table must know about such things. */ /* Character class & ref repeats */ \ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \ 1+2*IMM2_SIZE, 1+2*IMM2_SIZE, /* CRRANGE, CRMINRANGE */ \ + 1, 1, 1, 1+2*IMM2_SIZE, /* Possessive *+, ++, ?+, CRPOSRANGE */ \ 1+(32/sizeof(pcre_uchar)), /* CLASS */ \ 1+(32/sizeof(pcre_uchar)), /* NCLASS */ \ 0, /* XCLASS - variable length */ \ 1+IMM2_SIZE, /* REF */ \ 1+IMM2_SIZE, /* REFI */ \ + 1+2*IMM2_SIZE, /* DNREF */ \ + 1+2*IMM2_SIZE, /* DNREFI */ \ 1+LINK_SIZE, /* RECURSE */ \ 2+2*LINK_SIZE, /* CALLOUT */ \ 1+LINK_SIZE, /* Alt */ \ @@ -1919,8 +2315,8 @@ in UTF-8 mode. The code that uses this table must know about such things. */ 1+LINK_SIZE+IMM2_SIZE, /* SCBRA */ \ 1+LINK_SIZE+IMM2_SIZE, /* SCBRAPOS */ \ 1+LINK_SIZE, /* SCOND */ \ - 1+IMM2_SIZE, 1+IMM2_SIZE, /* CREF, NCREF */ \ - 1+IMM2_SIZE, 1+IMM2_SIZE, /* RREF, NRREF */ \ + 1+IMM2_SIZE, 1+2*IMM2_SIZE, /* CREF, DNCREF */ \ + 1+IMM2_SIZE, 1+2*IMM2_SIZE, /* RREF, DNRREF */ \ 1, /* DEF */ \ 1, 1, 1, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ \ 3, 1, 3, /* MARK, PRUNE, PRUNE_ARG */ \ @@ -1929,8 +2325,7 @@ in UTF-8 mode. The code that uses this table must know about such things. */ 1, 1, 1, 1, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */ \ 1+IMM2_SIZE, 1 /* CLOSE, SKIPZERO */ -/* A magic value for OP_RREF and OP_NRREF to indicate the "any recursion" -condition. */ +/* A magic value for OP_RREF to indicate the "any recursion" condition. */ #define RREF_ANY 0xffff @@ -1945,9 +2340,11 @@ enum { ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, - ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERRCOUNT }; + ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, + ERR80, ERR81, ERR82, ERR83, ERR84, 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_MODES }; @@ -1955,42 +2352,94 @@ enum { JIT_COMPILE, JIT_PARTIAL_SOFT_COMPILE, JIT_PARTIAL_HARD_COMPILE, 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 then run on another where the size of pointers is different, all might still -be well. For the case of compiled-on-4 and run-on-8, we include an extra -pointer that is always NULL. For future-proofing, a few dummy fields were -originally included - even though you can never get this planning right - but -there is only one left now. +be well. -NOTE NOTE NOTE: -Because people can now save and re-use compiled patterns, any additions to this -structure should be made at the end, and something earlier (e.g. a new -flag in the options or one of the dummy fields) should indicate that the new -fields are present. Currently PCRE always sets the dummy fields to zero. -NOTE NOTE NOTE +The size of the structure must be a multiple of 8 bytes. For the case of +compiled-on-4 and run-on-8, we include an extra pointer that is always NULL so +that there are an even number of pointers which therefore are a multiple of 8 +bytes. + +It is necessary to fork the struct for the 32 bit library, since it needs to +use pcre_uint32 for first_char and req_char. We can't put an ifdef inside the +typedef because pcretest needs access to the struct of the 8-, 16- and 32-bit +variants. + +*** WARNING *** +When new fields are added to these structures, remember to adjust the code in +pcre_byte_order.c that is concerned with swapping the byte order of the fields +when a compiled regex is reloaded on a host with different endianness. +*** WARNING *** +There is also similar byte-flipping code in pcretest.c, which is used for +testing the byte-flipping features. It must also be kept in step. +*** WARNING *** */ -#ifdef COMPILE_PCRE8 -#define REAL_PCRE real_pcre -#else -#define REAL_PCRE real_pcre16 -#endif - -typedef struct REAL_PCRE { +typedef struct real_pcre8_or_16 { pcre_uint32 magic_number; pcre_uint32 size; /* Total that was malloced */ pcre_uint32 options; /* Public options */ - pcre_uint16 flags; /* Private flags */ + pcre_uint32 flags; /* Private flags */ + pcre_uint32 limit_match; /* Limit set from regex */ + pcre_uint32 limit_recursion; /* Limit set from regex */ + pcre_uint16 first_char; /* Starting character */ + pcre_uint16 req_char; /* This character must be seen */ pcre_uint16 max_lookbehind; /* Longest lookbehind (characters) */ pcre_uint16 top_bracket; /* Highest numbered group */ pcre_uint16 top_backref; /* Highest numbered back reference */ - pcre_uint16 first_char; /* Starting character */ - pcre_uint16 req_char; /* This character must be seen */ pcre_uint16 name_table_offset; /* Offset to name table that follows */ pcre_uint16 name_entry_size; /* Size of any name items */ pcre_uint16 name_count; /* Number of name items */ pcre_uint16 ref_count; /* Reference count */ + pcre_uint16 dummy1; /* To ensure size is a multiple of 8 */ + pcre_uint16 dummy2; /* To ensure size is a multiple of 8 */ + pcre_uint16 dummy3; /* To ensure size is a multiple of 8 */ const pcre_uint8 *tables; /* Pointer to tables or NULL for std */ - const pcre_uint8 *nullpad; /* NULL padding */ -} REAL_PCRE; + void *nullpad; /* NULL padding */ +} real_pcre8_or_16; + +typedef struct real_pcre8_or_16 real_pcre; +typedef struct real_pcre8_or_16 real_pcre16; + +typedef struct real_pcre32 { + pcre_uint32 magic_number; + pcre_uint32 size; /* Total that was malloced */ + pcre_uint32 options; /* Public options */ + pcre_uint32 flags; /* Private flags */ + pcre_uint32 limit_match; /* Limit set from regex */ + pcre_uint32 limit_recursion; /* Limit set from regex */ + pcre_uint32 first_char; /* Starting character */ + pcre_uint32 req_char; /* This character must be seen */ + pcre_uint16 max_lookbehind; /* Longest lookbehind (characters) */ + pcre_uint16 top_bracket; /* Highest numbered group */ + pcre_uint16 top_backref; /* Highest numbered back reference */ + pcre_uint16 name_table_offset; /* Offset to name table that follows */ + pcre_uint16 name_entry_size; /* Size of any name items */ + pcre_uint16 name_count; /* Number of name items */ + pcre_uint16 ref_count; /* Reference count */ + pcre_uint16 dummy; /* To ensure size is a multiple of 8 */ + const pcre_uint8 *tables; /* Pointer to tables or NULL for std */ + void *nullpad; /* NULL padding */ +} real_pcre32; + +#if defined COMPILE_PCRE8 +#define REAL_PCRE real_pcre +#elif defined COMPILE_PCRE16 +#define REAL_PCRE real_pcre16 +#elif defined COMPILE_PCRE32 +#define REAL_PCRE real_pcre32 +#endif + +/* Assert that the size of REAL_PCRE is divisible by 8 */ +typedef int __assert_real_pcre_size_divisible_8[(sizeof(REAL_PCRE) % 8) == 0 ? 1 : -1]; + +/* Needed in pcretest to access some fields in the real_pcre* structures + * directly. They're unified for 8/16/32 bits since the structs only differ + * after these fields; if that ever changes, need to fork those defines into + * 8/16 and 32 bit versions. */ +#define REAL_PCRE_MAGIC(re) (((REAL_PCRE*)re)->magic_number) +#define REAL_PCRE_SIZE(re) (((REAL_PCRE*)re)->size) +#define REAL_PCRE_OPTIONS(re) (((REAL_PCRE*)re)->options) +#define REAL_PCRE_FLAGS(re) (((REAL_PCRE*)re)->flags) /* The format of the block used to store data from pcre_study(). The same remark (see NOTE above) about extending this structure applies. */ @@ -2013,6 +2462,15 @@ typedef struct open_capitem { pcre_uint16 flag; /* Set TRUE if recursive back ref */ } open_capitem; +/* Structure for building a list of named groups during the first pass of +compiling. */ + +typedef struct named_group { + const pcre_uchar *name; /* Points to the name in the pattern */ + int length; /* Length of the name */ + pcre_uint32 number; /* Group number */ +} named_group; + /* Structure for passing "static" information around between the functions doing the compiling, so that they are thread-safe. */ @@ -2025,23 +2483,29 @@ typedef struct compile_data { const pcre_uchar *start_code; /* The start of the compiled code */ const pcre_uchar *start_pattern; /* The start of the pattern */ const pcre_uchar *end_pattern; /* The end of the pattern */ - open_capitem *open_caps; /* Chain of open capture items */ pcre_uchar *hwm; /* High watermark of workspace */ + open_capitem *open_caps; /* Chain of open capture items */ + named_group *named_groups; /* Points to vector in pre-compile */ pcre_uchar *name_table; /* The name/number table */ int names_found; /* Number of entries so far */ int name_entry_size; /* Size of each entry */ + int named_group_list_size; /* Number of entries in the list */ int workspace_size; /* Size of workspace */ - int bracount; /* Count of capturing parens as we compile */ + unsigned int bracount; /* Count of capturing parens as we compile */ int final_bracount; /* Saved value after first pass */ int max_lookbehind; /* Maximum lookbehind (characters) */ int top_backref; /* Maximum back reference */ unsigned int backref_map; /* Bitmap of low back refs */ + unsigned int namedrefcount; /* Number of backreferences by name */ + int parens_depth; /* Depth of nested parentheses */ int assert_depth; /* Depth of nested assertions */ - int external_options; /* External (initial) options */ - int external_flags; /* External flag bits to be set */ + pcre_uint32 external_options; /* External (initial) options */ + pcre_uint32 external_flags; /* External flag bits to be set */ int req_varyopt; /* "After variable item" flag for reqbyte */ BOOL had_accept; /* (*ACCEPT) encountered */ + BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ BOOL check_lookbehind; /* Lookbehinds need later checking */ + BOOL dupnames; /* Duplicate names exist */ int nltype; /* Newline type */ int nllen; /* Newline string length */ pcre_uchar nl[4]; /* Newline string when fixed length */ @@ -2060,9 +2524,10 @@ call within the pattern; used by pcre_exec(). */ typedef struct recursion_info { struct recursion_info *prevrec; /* Previous recursion record (or NULL) */ - int group_num; /* Number of group that was called */ + unsigned int group_num; /* Number of group that was called */ int *offset_save; /* Pointer to start of saved offsets */ int saved_max; /* Number of saved offsets */ + int saved_capture_last; /* Last capture number */ PCRE_PUCHAR subject_position; /* Position at start of recursion */ } recursion_info; @@ -2099,12 +2564,13 @@ typedef struct match_data { int nllen; /* Newline string length */ int name_count; /* Number of names in name table */ int name_entry_size; /* Size of entry in names table */ + unsigned int skip_arg_count; /* For counting SKIP_ARGs */ + unsigned int ignore_skip_arg; /* For re-run when SKIP arg name not found */ pcre_uchar *name_table; /* Table of names */ pcre_uchar nl[4]; /* Newline string when fixed */ const pcre_uint8 *lcc; /* Points to lower casing table */ const pcre_uint8 *fcc; /* Points to case-flipping table */ const pcre_uint8 *ctypes; /* Points to table of type maps */ - BOOL offset_overflow; /* Set if too many extractions */ BOOL notbol; /* NOTBOL flag */ BOOL noteol; /* NOTEOL flag */ BOOL utf; /* UTF-8 / UTF-16 flag */ @@ -2116,7 +2582,6 @@ typedef struct match_data { BOOL hitend; /* Hit the end of the subject at some point */ BOOL bsr_anycrlf; /* \R is just any CRLF, not full Unicode */ BOOL hasthen; /* Pattern contains (*THEN) */ - BOOL ignore_skip_arg; /* For re-run when SKIP name not found */ const pcre_uchar *start_code; /* For use when recursing */ PCRE_PUCHAR start_subject; /* Start of the subject string */ PCRE_PUCHAR end_subject; /* End of the subject string */ @@ -2125,7 +2590,7 @@ typedef struct match_data { PCRE_PUCHAR start_used_ptr; /* Earliest consulted character */ int partial; /* PARTIAL options */ int end_offset_top; /* Highwater mark at end of match */ - int capture_last; /* Most recent capture number */ + pcre_int32 capture_last; /* Most recent capture number + overflow flag */ int start_offset; /* The start offset value */ int match_function_type; /* Set for certain special calls of MATCH() */ eptrblock *eptrchain; /* Chain of eptrblocks for tail recursions */ @@ -2194,25 +2659,30 @@ total length. */ /* Internal function and data prefixes. */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 #ifndef PUBL #define PUBL(name) pcre_##name #endif #ifndef PRIV #define PRIV(name) _pcre_##name #endif -#else /* COMPILE_PCRE8 */ -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 #ifndef PUBL #define PUBL(name) pcre16_##name #endif #ifndef PRIV #define PRIV(name) _pcre16_##name #endif +#elif defined COMPILE_PCRE32 +#ifndef PUBL +#define PUBL(name) pcre32_##name +#endif +#ifndef PRIV +#define PRIV(name) _pcre32_##name +#endif #else #error Unsupported compiling mode -#endif /* COMPILE_PCRE16 */ -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE[8|16|32] */ /* Layout of the UCP type table that translates property names into types and codes. Each entry used to point directly to a name, but to reduce the number of @@ -2232,22 +2702,22 @@ but are not part of the PCRE public API. The data for these tables is in the pcre_tables.c module. */ #ifdef COMPILE_PCRE8 - extern const int PRIV(utf8_table1)[]; extern const int PRIV(utf8_table1_size); extern const int PRIV(utf8_table2)[]; extern const int PRIV(utf8_table3)[]; extern const pcre_uint8 PRIV(utf8_table4)[]; - #endif /* COMPILE_PCRE8 */ extern const char PRIV(utt_names)[]; extern const ucp_type_table PRIV(utt)[]; extern const int PRIV(utt_size); +extern const pcre_uint8 PRIV(OP_lengths)[]; extern const pcre_uint8 PRIV(default_tables)[]; -extern const pcre_uint8 PRIV(OP_lengths)[]; +extern const pcre_uint32 PRIV(hspace_list)[]; +extern const pcre_uint32 PRIV(vspace_list)[]; /* Internal shared functions. These are functions that are used by more than @@ -2255,7 +2725,7 @@ one of the exported public functions. They have to be "external" in the C sense, but are not part of the PCRE public API. */ /* String comparison functions. */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 #define STRCMP_UC_UC(str1, str2) \ strcmp((char *)(str1), (char *)(str2)) @@ -2267,7 +2737,7 @@ sense, but are not part of the PCRE public API. */ strncmp((char *)(str1), (str2), (num)) #define STRLEN_UC(str) strlen((const char *)str) -#else +#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 extern int PRIV(strcmp_uc_uc)(const pcre_uchar *, const pcre_uchar *); @@ -2289,21 +2759,40 @@ extern unsigned int PRIV(strlen_uc)(const pcre_uchar *str); PRIV(strncmp_uc_c8)((str1), (str2), (num)) #define STRLEN_UC(str) PRIV(strlen_uc)(str) -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE[8|16|32] */ + +#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 + +#define STRCMP_UC_UC_TEST(str1, str2) STRCMP_UC_UC(str1, str2) +#define STRCMP_UC_C8_TEST(str1, str2) STRCMP_UC_C8(str1, str2) + +#elif defined COMPILE_PCRE32 + +extern int PRIV(strcmp_uc_uc_utf)(const pcre_uchar *, + const pcre_uchar *); +extern int PRIV(strcmp_uc_c8_utf)(const pcre_uchar *, + const char *); + +#define STRCMP_UC_UC_TEST(str1, str2) \ + (utf ? PRIV(strcmp_uc_uc_utf)((str1), (str2)) : PRIV(strcmp_uc_uc)((str1), (str2))) +#define STRCMP_UC_C8_TEST(str1, str2) \ + (utf ? PRIV(strcmp_uc_c8_utf)((str1), (str2)) : PRIV(strcmp_uc_c8)((str1), (str2))) + +#endif /* COMPILE_PCRE[8|16|32] */ extern const pcre_uchar *PRIV(find_bracket)(const pcre_uchar *, BOOL, int); extern BOOL PRIV(is_newline)(PCRE_PUCHAR, int, PCRE_PUCHAR, int *, BOOL); -extern int PRIV(ord2utf)(pcre_uint32, pcre_uchar *); +extern unsigned int PRIV(ord2utf)(pcre_uint32, pcre_uchar *); extern int PRIV(valid_utf)(PCRE_PUCHAR, int, int *); extern BOOL PRIV(was_newline)(PCRE_PUCHAR, int, PCRE_PUCHAR, int *, BOOL); -extern BOOL PRIV(xclass)(int, const pcre_uchar *, BOOL); +extern BOOL PRIV(xclass)(pcre_uint32, const pcre_uchar *, BOOL); #ifdef SUPPORT_JIT extern void PRIV(jit_compile)(const REAL_PCRE *, PUBL(extra) *, int); -extern int PRIV(jit_exec)(const REAL_PCRE *, const PUBL(extra) *, +extern int PRIV(jit_exec)(const PUBL(extra) *, const pcre_uchar *, int, int, int, int *, int); extern void PRIV(jit_free)(void *); extern int PRIV(jit_get_size)(void *); @@ -2313,15 +2802,19 @@ extern const char* PRIV(jit_get_target)(void); /* Unicode character database (UCD) */ typedef struct { - pcre_uint8 script; - pcre_uint8 chartype; - pcre_int32 other_case; + pcre_uint8 script; /* ucp_Arabic, etc. */ + pcre_uint8 chartype; /* ucp_Cc, etc. (general categories) */ + pcre_uint8 gbprop; /* ucp_gbControl, etc. (grapheme break property) */ + pcre_uint8 caseset; /* offset to multichar other cases or zero */ + pcre_int32 other_case; /* offset to other case, or zero if none */ } ucd_record; +extern const pcre_uint32 PRIV(ucd_caseless_sets)[]; extern const ucd_record PRIV(ucd_records)[]; extern const pcre_uint8 PRIV(ucd_stage1)[]; extern const pcre_uint16 PRIV(ucd_stage2)[]; -extern const int PRIV(ucp_gentype)[]; +extern const pcre_uint32 PRIV(ucp_gentype)[]; +extern const pcre_uint32 PRIV(ucp_gbtable)[]; #ifdef SUPPORT_JIT extern const int PRIV(ucp_typerange)[]; #endif @@ -2331,13 +2824,15 @@ extern const int PRIV(ucp_typerange)[]; #define UCD_BLOCK_SIZE 128 #define GET_UCD(ch) (PRIV(ucd_records) + \ - PRIV(ucd_stage2)[PRIV(ucd_stage1)[(ch) / UCD_BLOCK_SIZE] * \ - UCD_BLOCK_SIZE + (ch) % UCD_BLOCK_SIZE]) + PRIV(ucd_stage2)[PRIV(ucd_stage1)[(int)(ch) / UCD_BLOCK_SIZE] * \ + UCD_BLOCK_SIZE + (int)(ch) % UCD_BLOCK_SIZE]) -#define UCD_CHARTYPE(ch) GET_UCD(ch)->chartype -#define UCD_SCRIPT(ch) GET_UCD(ch)->script -#define UCD_CATEGORY(ch) PRIV(ucp_gentype)[UCD_CHARTYPE(ch)] -#define UCD_OTHERCASE(ch) (ch + GET_UCD(ch)->other_case) +#define UCD_CHARTYPE(ch) GET_UCD(ch)->chartype +#define UCD_SCRIPT(ch) GET_UCD(ch)->script +#define UCD_CATEGORY(ch) PRIV(ucp_gentype)[UCD_CHARTYPE(ch)] +#define UCD_GRAPHBREAK(ch) GET_UCD(ch)->gbprop +#define UCD_CASESET(ch) GET_UCD(ch)->caseset +#define UCD_OTHERCASE(ch) ((pcre_uint32)((int)ch + (int)(GET_UCD(ch)->other_case))) #endif /* SUPPORT_UCP */ diff --git a/src/3rd/pcre/pcrejitc.c b/src/3rd/pcre/pcrejitc.c index fe2d9f7b16..c511468513 100644 --- a/src/3rd/pcre/pcrejitc.c +++ b/src/3rd/pcre/pcrejitc.c @@ -6,10 +6,10 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2012 University of Cambridge + Copyright (c) 1997-2013 University of Cambridge The machine code generator part (this module) was written by Zoltan Herczeg - Copyright (c) 2010-2012 + Copyright (c) 2010-2013 ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -46,7 +46,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "pcreinal.h" -#ifdef SUPPORT_JIT +#if defined SUPPORT_JIT /* All-in-one: Since we use the JIT compiler only from here, we just include it. This way we don't need to touch the build @@ -65,9 +65,21 @@ system files. */ #error Unsupported architecture #endif -/* Allocate memory on the stack. Fast, but limited size. */ -#define LOCAL_SPACE_SIZE 32768 +/* Defines for debugging purposes. */ +/* 1 - Use unoptimized capturing brackets. + 2 - Enable capture_last_ptr (includes option 1). */ +/* #define DEBUG_FORCE_UNOPTIMIZED_CBRAS 2 */ + +/* 1 - Always have a control head. */ +/* #define DEBUG_FORCE_CONTROL_HEAD 1 */ + +/* Allocate memory for the regex stack on the real machine stack. +Fast, but limited size. */ +#define MACHINE_STACK_SIZE 32768 + +/* Growth rate for stack allocated by the OS. Should be the multiply +of page size. */ #define STACK_GROWTH_RATE 8192 /* Enable to check that the allocation could destroy temporaries. */ @@ -89,15 +101,15 @@ vertical (sub-expression) (See struct backtrack_common for more details). The condition checkers are boolean (true/false) checkers. Machine code is generated for the checker itself and for the actions depending on the result of the checker. -The 'true' case is called as the try path (expected path), and the other is called as +The 'true' case is called as the matching path (expected path), and the other is called as the 'backtrack' path. Branch instructions are expesive for all CPUs, so we avoid taken -branches on the try path. +branches on the matching path. Greedy star operator (*) : - Try path: match happens. + Matching path: match happens. Backtrack path: match failed. Non-greedy star operator (*?) : - Try path: no need to perform a match. + Matching path: no need to perform a match. Backtrack path: match is required. The following example shows how the code generated for a capturing bracket @@ -108,18 +120,18 @@ we have the following regular expression: The generated code will be the following: - A try path - '(' try path (pushing arguments to the stack) - B try path - ')' try path (pushing arguments to the stack) - D try path + A matching path + '(' matching path (pushing arguments to the stack) + B matching path + ')' matching path (pushing arguments to the stack) + D matching path return with successful match D backtrack path ')' backtrack path (If we arrived from "C" jump to the backtrack of "C") B backtrack path C expected path - jump to D try path + jump to D matching path C backtrack path A backtrack path @@ -127,22 +139,22 @@ The generated code will be the following: code paths. In this way the topmost value on the stack is always belong to the current backtrack code path. The backtrack path must check whether there is a next alternative. If so, it needs to jump back to - the try path eventually. Otherwise it needs to clear out its own stack + the matching path eventually. Otherwise it needs to clear out its own stack frame and continue the execution on the backtrack code paths. */ /* Saved stack frames: -Atomic blocks and asserts require reloading the values of local variables -when the backtrack mechanism performed. Because of OP_RECURSE, the locals +Atomic blocks and asserts require reloading the values of private data +when the backtrack mechanism performed. Because of OP_RECURSE, the data are not necessarly known in compile time, thus we need a dynamic restore mechanism. The stack frames are stored in a chain list, and have the following format: ([ capturing bracket offset ][ start value ][ end value ])+ ... [ 0 ] [ previous head ] -Thus we can restore the locals to a particular point in the stack. +Thus we can restore the private data to a particular point in the stack. */ typedef struct jit_arguments { @@ -154,9 +166,11 @@ typedef struct jit_arguments { int *offsets; pcre_uchar *uchar_ptr; pcre_uchar *mark_ptr; + void *callout_data; /* Everything else after. */ - int offsetcount; - int calllimit; + pcre_uint32 limit_match; + int real_offset_count; + int offset_count; pcre_uint8 notbol; pcre_uint8 noteol; pcre_uint8 notempty; @@ -167,6 +181,8 @@ typedef struct executable_functions { void *executable_funcs[JIT_NUMBER_OF_COMPILE_MODES]; PUBL(jit_callback) callback; void *userdata; + pcre_uint32 top_bracket; + pcre_uint32 limit_match; sljit_uw executable_sizes[JIT_NUMBER_OF_COMPILE_MODES]; } executable_functions; @@ -175,21 +191,27 @@ typedef struct jump_list { struct jump_list *next; } jump_list; -enum stub_types { stack_alloc }; - typedef struct stub_list { - enum stub_types type; - int data; struct sljit_jump *start; - struct sljit_label *leave; + struct sljit_label *quit; struct stub_list *next; } stub_list; +enum frame_types { + no_frame = -1, + no_stack = -2 +}; + +enum control_types { + type_mark = 0, + type_then_trap = 1 +}; + typedef int (SLJIT_CALL *jit_function)(jit_arguments *args); /* The following structure is the key data type for the recursive -code generator. It is allocated by compile_trypath, and contains -the aguments for compile_backtrackpath. Must be the first member +code generator. It is allocated by compile_matchingpath, and contains +the arguments for compile_backtrackingpath. Must be the first member of its descendants. */ typedef struct backtrack_common { /* Concatenation stack. */ @@ -205,38 +227,38 @@ typedef struct backtrack_common { typedef struct assert_backtrack { backtrack_common common; jump_list *condfailed; - /* Less than 0 (-1) if a frame is not needed. */ + /* Less than 0 if a frame is not needed. */ int framesize; /* Points to our private memory word on the stack. */ - int localptr; + int private_data_ptr; /* For iterators. */ - struct sljit_label *trypath; + struct sljit_label *matchingpath; } assert_backtrack; typedef struct bracket_backtrack { backtrack_common common; /* Where to coninue if an alternative is successfully matched. */ - struct sljit_label *alttrypath; + struct sljit_label *alternative_matchingpath; /* For rmin and rmax iterators. */ - struct sljit_label *recursivetrypath; + struct sljit_label *recursive_matchingpath; /* For greedy ? operator. */ - struct sljit_label *zerotrypath; + struct sljit_label *zero_matchingpath; /* Contains the branches of a failed condition. */ union { /* Both for OP_COND, OP_SCOND. */ jump_list *condfailed; assert_backtrack *assert; - /* For OP_ONCE. -1 if not needed. */ + /* For OP_ONCE. Less than 0 if not needed. */ int framesize; } u; /* Points to our private memory word on the stack. */ - int localptr; + int private_data_ptr; } bracket_backtrack; typedef struct bracketpos_backtrack { backtrack_common common; /* Points to our private memory word on the stack. */ - int localptr; + int private_data_ptr; /* Reverting stack is needed. */ int framesize; /* Allocated stack size. */ @@ -245,13 +267,13 @@ typedef struct bracketpos_backtrack { typedef struct braminzero_backtrack { backtrack_common common; - struct sljit_label *trypath; + struct sljit_label *matchingpath; } braminzero_backtrack; typedef struct iterator_backtrack { backtrack_common common; /* Next iteration. */ - struct sljit_label *trypath; + struct sljit_label *matchingpath; } iterator_backtrack; typedef struct recurse_entry { @@ -261,26 +283,52 @@ typedef struct recurse_entry { /* Collects the calls until the function is not created. */ jump_list *calls; /* Points to the starting opcode. */ - int start; + sljit_sw start; } recurse_entry; typedef struct recurse_backtrack { backtrack_common common; + BOOL inlined_pattern; } recurse_backtrack; -typedef struct compiler_common { - struct sljit_compiler *compiler; - pcre_uchar *start; +#define OP_THEN_TRAP OP_TABLE_LENGTH - /* Opcode local area direct map. */ - int *localptrs; - int cbraptr; - /* OVector starting point. Must be divisible by 2. */ +typedef struct then_trap_backtrack { + backtrack_common common; + /* If then_trap is not NULL, this structure contains the real + then_trap for the backtracking path. */ + struct then_trap_backtrack *then_trap; + /* Points to the starting opcode. */ + sljit_sw start; + /* Exit point for the then opcodes of this alternative. */ + jump_list *quit; + /* Frame size of the current alternative. */ + int framesize; +} then_trap_backtrack; + +#define MAX_RANGE_SIZE 6 + +typedef struct compiler_common { + /* The sljit ceneric compiler. */ + struct sljit_compiler *compiler; + /* First byte code. */ + pcre_uchar *start; + /* Maps private data offset to each opcode. */ + sljit_si *private_data_ptrs; + /* Tells whether the capturing bracket is optimized. */ + pcre_uint8 *optimized_cbracket; + /* Tells whether the starting offset is a target of then. */ + pcre_uint8 *then_offsets; + /* Current position where a THEN must jump. */ + then_trap_backtrack *then_trap; + /* Starting offset of private data for capturing brackets. */ + int cbra_ptr; + /* Output vector starting point. Must be divisible by 2. */ int ovector_start; /* Last known position of the requested byte. */ int req_char_ptr; /* Head of the last recursion. */ - int recursive_head; + int recursive_head_ptr; /* First inspected character for partial matching. */ int start_used_ptr; /* Starting pointer for partial soft matches. */ @@ -289,30 +337,56 @@ typedef struct compiler_common { int first_line_end; /* Points to the marked string. */ int mark_ptr; + /* Recursive control verb management chain. */ + int control_head_ptr; + /* Points to the last matched capture block index. */ + int capture_last_ptr; + /* Points to the starting position of the current match. */ + int start_ptr; - /* Other */ + /* Flipped and lower case tables. */ const pcre_uint8 *fcc; - sljit_w lcc; + sljit_sw lcc; + /* Mode can be PCRE_STUDY_JIT_COMPILE and others. */ int mode; + /* \K is found in the pattern. */ + BOOL has_set_som; + /* (*SKIP:arg) is found in the pattern. */ + BOOL has_skip_arg; + /* (*THEN) is found in the pattern. */ + BOOL has_then; + /* Needs to know the start position anytime. */ + BOOL needs_start_ptr; + /* Currently in recurse or negative assert. */ + BOOL local_exit; + /* Currently in a positive assert. */ + BOOL positive_assert; + /* Newline control. */ int nltype; int newline; int bsr_nltype; + /* Dollar endonly. */ int endonly; - BOOL has_set_som; - sljit_w ctypes; - sljit_uw name_table; - sljit_w name_count; - sljit_w name_entry_size; + /* Tables. */ + sljit_sw ctypes; + int digits[2 + MAX_RANGE_SIZE]; + /* Named capturing brackets. */ + pcre_uchar *name_table; + sljit_sw name_count; + sljit_sw name_entry_size; /* Labels and jump lists. */ struct sljit_label *partialmatchlabel; - struct sljit_label *leavelabel; - struct sljit_label *acceptlabel; + struct sljit_label *quit_label; + struct sljit_label *forced_quit_label; + struct sljit_label *accept_label; stub_list *stubs; recurse_entry *entries; recurse_entry *currententry; jump_list *partialmatch; - jump_list *leave; + jump_list *quit; + jump_list *positive_assert_quit; + jump_list *forced_quit; jump_list *accept; jump_list *calllimit; jump_list *stackalloc; @@ -323,13 +397,16 @@ typedef struct compiler_common { jump_list *vspace; jump_list *casefulcmp; jump_list *caselesscmp; + jump_list *reset_match; BOOL jscript_compat; #ifdef SUPPORT_UTF BOOL utf; #ifdef SUPPORT_UCP BOOL use_ucp; #endif +#ifndef COMPILE_PCRE32 jump_list *utfreadchar; +#endif #ifdef COMPILE_PCRE8 jump_list *utfreadtype8; #endif @@ -347,84 +424,79 @@ typedef struct compare_context { #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED int ucharptr; union { - sljit_i asint; + sljit_si asint; sljit_uh asushort; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 sljit_ub asbyte; sljit_ub asuchars[4]; -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 sljit_uh asuchars[2]; -#endif +#elif defined COMPILE_PCRE32 + sljit_ui asuchars[1]; #endif } c; union { - sljit_i asint; + sljit_si asint; sljit_uh asushort; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 sljit_ub asbyte; sljit_ub asuchars[4]; -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 sljit_uh asuchars[2]; -#endif +#elif defined COMPILE_PCRE32 + sljit_ui asuchars[1]; #endif } oc; #endif } compare_context; -enum { - frame_end = 0, - frame_setstrbegin = -1, - frame_setmark = -2 -}; - /* Undefine sljit macros. */ #undef CMP /* Used for accessing the elements of the stack. */ -#define STACK(i) ((-(i) - 1) * (int)sizeof(sljit_w)) +#define STACK(i) ((-(i) - 1) * (int)sizeof(sljit_sw)) -#define TMP1 SLJIT_TEMPORARY_REG1 -#define TMP2 SLJIT_TEMPORARY_REG3 +#define TMP1 SLJIT_SCRATCH_REG1 +#define TMP2 SLJIT_SCRATCH_REG3 #define TMP3 SLJIT_TEMPORARY_EREG2 #define STR_PTR SLJIT_SAVED_REG1 #define STR_END SLJIT_SAVED_REG2 -#define STACK_TOP SLJIT_TEMPORARY_REG2 +#define STACK_TOP SLJIT_SCRATCH_REG2 #define STACK_LIMIT SLJIT_SAVED_REG3 #define ARGUMENTS SLJIT_SAVED_EREG1 -#define CALL_COUNT SLJIT_SAVED_EREG2 +#define COUNT_MATCH SLJIT_SAVED_EREG2 #define RETURN_ADDR SLJIT_TEMPORARY_EREG1 -/* Locals layout. */ +/* Local space layout. */ /* These two locals can be used by the current opcode. */ -#define LOCALS0 (0 * sizeof(sljit_w)) -#define LOCALS1 (1 * sizeof(sljit_w)) +#define LOCALS0 (0 * sizeof(sljit_sw)) +#define LOCALS1 (1 * sizeof(sljit_sw)) /* Two local variables for possessive quantifiers (char1 cannot use them). */ -#define POSSESSIVE0 (2 * sizeof(sljit_w)) -#define POSSESSIVE1 (3 * sizeof(sljit_w)) +#define POSSESSIVE0 (2 * sizeof(sljit_sw)) +#define POSSESSIVE1 (3 * sizeof(sljit_sw)) /* Max limit of recursions. */ -#define CALL_LIMIT (4 * sizeof(sljit_w)) +#define LIMIT_MATCH (4 * sizeof(sljit_sw)) /* 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 (common->ovector_start) -#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]) +#define OVECTOR(i) (OVECTOR_START + (i) * (sljit_sw)sizeof(sljit_sw)) +#define OVECTOR_PRIV(i) (common->cbra_ptr + (i) * (sljit_sw)sizeof(sljit_sw)) +#define PRIVATE_DATA(cc) (common->private_data_ptrs[(cc) - common->start]) -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 #define MOV_UCHAR SLJIT_MOV_UB #define MOVU_UCHAR SLJIT_MOVU_UB -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 #define MOV_UCHAR SLJIT_MOV_UH #define MOVU_UCHAR SLJIT_MOVU_UH +#elif defined COMPILE_PCRE32 +#define MOV_UCHAR SLJIT_MOV_UI +#define MOVU_UCHAR SLJIT_MOVU_UI #else #error Unsupported compiling mode #endif -#endif /* Shortcuts. */ #define DEFINE_COMPILER \ @@ -441,12 +513,14 @@ the start pointers when the end of the capturing group has not yet reached. */ sljit_set_label(sljit_emit_jump(compiler, (type)), (label)) #define JUMPHERE(jump) \ sljit_set_label((jump), sljit_emit_label(compiler)) +#define SET_LABEL(jump, label) \ + sljit_set_label((jump), (label)) #define CMP(type, src1, src1w, src2, src2w) \ sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)) #define CMPTO(type, src1, src1w, src2, src2w, label) \ sljit_set_label(sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)), (label)) -#define COND_VALUE(op, dst, dstw, type) \ - sljit_emit_cond_value(compiler, (op), (dst), (dstw), (type)) +#define OP_FLAGS(op, dst, dstw, src, srcw, type) \ + sljit_emit_op_flags(compiler, (op), (dst), (dstw), (src), (srcw), (type)) #define GET_LOCAL_BASE(dst, dstw, offset) \ sljit_get_local_base(compiler, (dst), (dstw), (offset)) @@ -461,14 +535,14 @@ return cc; /* Functions whose might need modification for all new supported opcodes: next_opcode - get_localspace - set_localptrs + check_opcode_types + set_private_data_ptrs get_framesize init_frame - get_localsize - copy_locals - compile_trypath - compile_backtrackpath + get_private_data_copy_length + copy_private_data + compile_matchingpath + compile_backtrackingpath */ static pcre_uchar *next_opcode(compiler_common *common, pcre_uchar *cc) @@ -489,6 +563,8 @@ switch(*cc) case OP_WORDCHAR: case OP_ANY: case OP_ALLANY: + case OP_NOTPROP: + case OP_PROP: case OP_ANYNL: case OP_NOT_HSPACE: case OP_HSPACE: @@ -501,37 +577,66 @@ switch(*cc) case OP_CIRCM: case OP_DOLL: case OP_DOLLM: - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - case OP_TYPEPOSSTAR: - case OP_TYPEPOSPLUS: - case OP_TYPEPOSQUERY: case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRRANGE: + case OP_CRMINRANGE: + case OP_CRPOSSTAR: + case OP_CRPOSPLUS: + case OP_CRPOSQUERY: + case OP_CRPOSRANGE: + case OP_CLASS: + case OP_NCLASS: + case OP_REF: + case OP_REFI: + case OP_DNREF: + case OP_DNREFI: + case OP_RECURSE: + case OP_CALLOUT: + case OP_ALT: + case OP_KET: + case OP_KETRMAX: + case OP_KETRMIN: + case OP_KETRPOS: + case OP_REVERSE: + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + case OP_ONCE: + case OP_ONCE_NC: + case OP_BRA: + case OP_BRAPOS: + case OP_CBRA: + case OP_CBRAPOS: + case OP_COND: + case OP_SBRA: + case OP_SBRAPOS: + case OP_SCBRA: + case OP_SCBRAPOS: + case OP_SCOND: + case OP_CREF: + case OP_DNCREF: + case OP_RREF: + case OP_DNRREF: case OP_DEF: case OP_BRAZERO: case OP_BRAMINZERO: case OP_BRAPOSZERO: + case OP_PRUNE: + case OP_SKIP: + case OP_THEN: case OP_COMMIT: case OP_FAIL: case OP_ACCEPT: case OP_ASSERT_ACCEPT: + case OP_CLOSE: case OP_SKIPZERO: - return cc + 1; - - case OP_ANYBYTE: -#ifdef SUPPORT_UTF - if (common->utf) return NULL; -#endif - return cc + 1; + return cc + PRIV(OP_lengths)[*cc]; case OP_CHAR: case OP_CHARI: @@ -543,134 +648,103 @@ switch(*cc) case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: + case OP_UPTO: + case OP_MINUPTO: + case OP_EXACT: case OP_POSSTAR: case OP_POSPLUS: case OP_POSQUERY: + case OP_POSUPTO: case OP_STARI: case OP_MINSTARI: case OP_PLUSI: case OP_MINPLUSI: case OP_QUERYI: case OP_MINQUERYI: + case OP_UPTOI: + case OP_MINUPTOI: + case OP_EXACTI: case OP_POSSTARI: case OP_POSPLUSI: case OP_POSQUERYI: + case OP_POSUPTOI: case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: + case OP_NOTUPTO: + case OP_NOTMINUPTO: + case OP_NOTEXACT: case OP_NOTPOSSTAR: case OP_NOTPOSPLUS: case OP_NOTPOSQUERY: + case OP_NOTPOSUPTO: case OP_NOTSTARI: case OP_NOTMINSTARI: case OP_NOTPLUSI: case OP_NOTMINPLUSI: case OP_NOTQUERYI: case OP_NOTMINQUERYI: - case OP_NOTPOSSTARI: - case OP_NOTPOSPLUSI: - case OP_NOTPOSQUERYI: - cc += 2; -#ifdef SUPPORT_UTF - if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); -#endif - return cc; - - case OP_UPTO: - case OP_MINUPTO: - case OP_EXACT: - case OP_POSUPTO: - case OP_UPTOI: - case OP_MINUPTOI: - case OP_EXACTI: - case OP_POSUPTOI: - case OP_NOTUPTO: - case OP_NOTMINUPTO: - case OP_NOTEXACT: - case OP_NOTPOSUPTO: case OP_NOTUPTOI: case OP_NOTMINUPTOI: case OP_NOTEXACTI: + case OP_NOTPOSSTARI: + case OP_NOTPOSPLUSI: + case OP_NOTPOSQUERYI: case OP_NOTPOSUPTOI: - cc += 2 + IMM2_SIZE; + cc += PRIV(OP_lengths)[*cc]; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif return cc; - case OP_NOTPROP: - case OP_PROP: - return cc + 1 + 2; - + /* Special cases. */ + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEEXACT: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: case OP_TYPEPOSUPTO: - case OP_REF: - case OP_REFI: - case OP_CREF: - case OP_NCREF: - case OP_RREF: - case OP_NRREF: - case OP_CLOSE: - cc += 1 + IMM2_SIZE; - return cc; + return cc + PRIV(OP_lengths)[*cc] - 1; - case OP_CRRANGE: - case OP_CRMINRANGE: - return cc + 1 + 2 * IMM2_SIZE; - - case OP_CLASS: - case OP_NCLASS: - return cc + 1 + 32 / sizeof(pcre_uchar); + case OP_ANYBYTE: +#ifdef SUPPORT_UTF + if (common->utf) return NULL; +#endif + return cc + 1; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: return cc + GET(cc, 1); #endif - case OP_RECURSE: - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_REVERSE: - case OP_ONCE: - case OP_ONCE_NC: - case OP_BRA: - case OP_BRAPOS: - case OP_COND: - case OP_SBRA: - case OP_SBRAPOS: - case OP_SCOND: - case OP_ALT: - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_KETRPOS: - return cc + 1 + LINK_SIZE; - - case OP_CBRA: - case OP_CBRAPOS: - case OP_SCBRA: - case OP_SCBRAPOS: - return cc + 1 + LINK_SIZE + IMM2_SIZE; - case OP_MARK: + case OP_PRUNE_ARG: + case OP_SKIP_ARG: + case OP_THEN_ARG: return cc + 1 + 2 + cc[1]; default: + /* All opcodes are supported now! */ + SLJIT_ASSERT_STOP(); return NULL; } } -static int get_localspace(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend) +static BOOL check_opcode_types(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend) { -int localspace = 0; -pcre_uchar *alternative; +int count; +pcre_uchar *slot; + /* Calculate important variables (like stack size) and checks whether all opcodes are supported. */ while (cc < ccend) { @@ -681,71 +755,308 @@ while (cc < ccend) cc += 1; break; - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - case OP_ONCE: - case OP_ONCE_NC: - case OP_BRAPOS: - case OP_SBRA: - case OP_SBRAPOS: - case OP_SCOND: - localspace += sizeof(sljit_w); - cc += 1 + LINK_SIZE; + case OP_REF: + case OP_REFI: + common->optimized_cbracket[GET2(cc, 1)] = 0; + cc += 1 + IMM2_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: - localspace += sizeof(sljit_w); + common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] = 0; cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_COND: - /* Might be a hidden SCOND. */ - alternative = cc + GET(cc, 1); - if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) - localspace += sizeof(sljit_w); + case OP_SCOND: + /* Only AUTO_CALLOUT can insert this opcode. We do + not intend to support this case. */ + if (cc[1 + LINK_SIZE] == OP_CALLOUT) + return FALSE; cc += 1 + LINK_SIZE; break; + case OP_CREF: + common->optimized_cbracket[GET2(cc, 1)] = 0; + cc += 1 + IMM2_SIZE; + break; + + case OP_DNREF: + case OP_DNREFI: + case OP_DNCREF: + count = GET2(cc, 1 + IMM2_SIZE); + slot = common->name_table + GET2(cc, 1) * common->name_entry_size; + while (count-- > 0) + { + common->optimized_cbracket[GET2(slot, 0)] = 0; + slot += common->name_entry_size; + } + cc += 1 + 2 * IMM2_SIZE; + break; + case OP_RECURSE: /* Set its value only once. */ - if (common->recursive_head == 0) + if (common->recursive_head_ptr == 0) { - common->recursive_head = common->ovector_start; - common->ovector_start += sizeof(sljit_w); + common->recursive_head_ptr = common->ovector_start; + common->ovector_start += sizeof(sljit_sw); } cc += 1 + LINK_SIZE; break; + case OP_CALLOUT: + if (common->capture_last_ptr == 0) + { + common->capture_last_ptr = common->ovector_start; + common->ovector_start += sizeof(sljit_sw); + } + cc += 2 + 2 * LINK_SIZE; + break; + + case OP_THEN_ARG: + common->has_then = TRUE; + common->control_head_ptr = 1; + /* Fall through. */ + + case OP_PRUNE_ARG: + common->needs_start_ptr = TRUE; + /* Fall through. */ + case OP_MARK: if (common->mark_ptr == 0) { common->mark_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_w); + common->ovector_start += sizeof(sljit_sw); } cc += 1 + 2 + cc[1]; break; + case OP_THEN: + common->has_then = TRUE; + common->control_head_ptr = 1; + /* Fall through. */ + + case OP_PRUNE: + case OP_SKIP: + common->needs_start_ptr = TRUE; + cc += 1; + break; + + case OP_SKIP_ARG: + common->control_head_ptr = 1; + common->has_skip_arg = TRUE; + cc += 1 + 2 + cc[1]; + break; + default: cc = next_opcode(common, cc); if (cc == NULL) - return -1; + return FALSE; break; } } -return localspace; +return TRUE; } -static void set_localptrs(compiler_common *common, int localptr, pcre_uchar *ccend) +static int get_class_iterator_size(pcre_uchar *cc) +{ +switch(*cc) + { + case OP_CRSTAR: + case OP_CRPLUS: + return 2; + + case OP_CRMINSTAR: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + return 1; + + case OP_CRRANGE: + case OP_CRMINRANGE: + if (GET2(cc, 1) == GET2(cc, 1 + IMM2_SIZE)) + return 0; + return 2; + + default: + return 0; + } +} + +static BOOL detect_repeat(compiler_common *common, pcre_uchar *begin) +{ +pcre_uchar *end = bracketend(begin); +pcre_uchar *next; +pcre_uchar *next_end; +pcre_uchar *max_end; +pcre_uchar type; +sljit_sw length = end - begin; +int min, max, i; + +/* Detect fixed iterations first. */ +if (end[-(1 + LINK_SIZE)] != OP_KET) + return FALSE; + +/* Already detected repeat. */ +if (common->private_data_ptrs[end - common->start - LINK_SIZE] != 0) + return TRUE; + +next = end; +min = 1; +while (1) + { + if (*next != *begin) + break; + next_end = bracketend(next); + if (next_end - next != length || memcmp(begin, next, IN_UCHARS(length)) != 0) + break; + next = next_end; + min++; + } + +if (min == 2) + return FALSE; + +max = 0; +max_end = next; +if (*next == OP_BRAZERO || *next == OP_BRAMINZERO) + { + type = *next; + while (1) + { + if (next[0] != type || next[1] != OP_BRA || next[2 + LINK_SIZE] != *begin) + break; + next_end = bracketend(next + 2 + LINK_SIZE); + if (next_end - next != (length + 2 + LINK_SIZE) || memcmp(begin, next + 2 + LINK_SIZE, IN_UCHARS(length)) != 0) + break; + next = next_end; + max++; + } + + if (next[0] == type && next[1] == *begin && max >= 1) + { + next_end = bracketend(next + 1); + if (next_end - next == (length + 1) && memcmp(begin, next + 1, IN_UCHARS(length)) == 0) + { + for (i = 0; i < max; i++, next_end += 1 + LINK_SIZE) + if (*next_end != OP_KET) + break; + + if (i == max) + { + common->private_data_ptrs[max_end - common->start - LINK_SIZE] = next_end - max_end; + common->private_data_ptrs[max_end - common->start - LINK_SIZE + 1] = (type == OP_BRAZERO) ? OP_UPTO : OP_MINUPTO; + /* +2 the original and the last. */ + common->private_data_ptrs[max_end - common->start - LINK_SIZE + 2] = max + 2; + if (min == 1) + return TRUE; + min--; + max_end -= (1 + LINK_SIZE) + GET(max_end, -LINK_SIZE); + } + } + } + } + +if (min >= 3) + { + common->private_data_ptrs[end - common->start - LINK_SIZE] = max_end - end; + common->private_data_ptrs[end - common->start - LINK_SIZE + 1] = OP_EXACT; + common->private_data_ptrs[end - common->start - LINK_SIZE + 2] = min; + return TRUE; + } + +return FALSE; +} + +#define CASE_ITERATOR_PRIVATE_DATA_1 \ + case OP_MINSTAR: \ + case OP_MINPLUS: \ + case OP_QUERY: \ + case OP_MINQUERY: \ + case OP_MINSTARI: \ + case OP_MINPLUSI: \ + case OP_QUERYI: \ + case OP_MINQUERYI: \ + case OP_NOTMINSTAR: \ + case OP_NOTMINPLUS: \ + case OP_NOTQUERY: \ + case OP_NOTMINQUERY: \ + case OP_NOTMINSTARI: \ + case OP_NOTMINPLUSI: \ + case OP_NOTQUERYI: \ + case OP_NOTMINQUERYI: + +#define CASE_ITERATOR_PRIVATE_DATA_2A \ + case OP_STAR: \ + case OP_PLUS: \ + case OP_STARI: \ + case OP_PLUSI: \ + case OP_NOTSTAR: \ + case OP_NOTPLUS: \ + case OP_NOTSTARI: \ + case OP_NOTPLUSI: + +#define CASE_ITERATOR_PRIVATE_DATA_2B \ + case OP_UPTO: \ + case OP_MINUPTO: \ + case OP_UPTOI: \ + case OP_MINUPTOI: \ + case OP_NOTUPTO: \ + case OP_NOTMINUPTO: \ + case OP_NOTUPTOI: \ + case OP_NOTMINUPTOI: + +#define CASE_ITERATOR_TYPE_PRIVATE_DATA_1 \ + case OP_TYPEMINSTAR: \ + case OP_TYPEMINPLUS: \ + case OP_TYPEQUERY: \ + case OP_TYPEMINQUERY: + +#define CASE_ITERATOR_TYPE_PRIVATE_DATA_2A \ + case OP_TYPESTAR: \ + case OP_TYPEPLUS: + +#define CASE_ITERATOR_TYPE_PRIVATE_DATA_2B \ + case OP_TYPEUPTO: \ + case OP_TYPEMINUPTO: + +static void set_private_data_ptrs(compiler_common *common, int *private_data_start, pcre_uchar *ccend) { pcre_uchar *cc = common->start; pcre_uchar *alternative; +pcre_uchar *end = NULL; +int private_data_ptr = *private_data_start; +int space, size, bracketlen; + while (cc < ccend) { + space = 0; + size = 0; + bracketlen = 0; + if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE) + return; + + if (*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 + based single character repeat is allowed. */ + if (cc >= end) + end = bracketend(cc); + } + switch(*cc) { + case OP_KET: + if (common->private_data_ptrs[cc + 1 - common->start] != 0) + { + common->private_data_ptrs[cc - common->start] = private_data_ptr; + private_data_ptr += sizeof(sljit_sw); + cc += common->private_data_ptrs[cc + 1 - common->start]; + } + cc += 1 + LINK_SIZE; + break; + case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: @@ -756,16 +1067,16 @@ while (cc < ccend) case OP_SBRA: case OP_SBRAPOS: case OP_SCOND: - common->localptrs[cc - common->start] = localptr; - localptr += sizeof(sljit_w); - cc += 1 + LINK_SIZE; + common->private_data_ptrs[cc - common->start] = private_data_ptr; + private_data_ptr += sizeof(sljit_sw); + bracketlen = 1 + LINK_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: - common->localptrs[cc - common->start] = localptr; - localptr += sizeof(sljit_w); - cc += 1 + LINK_SIZE + IMM2_SIZE; + common->private_data_ptrs[cc - common->start] = private_data_ptr; + private_data_ptr += sizeof(sljit_sw); + bracketlen = 1 + LINK_SIZE + IMM2_SIZE; break; case OP_COND: @@ -773,42 +1084,144 @@ while (cc < ccend) alternative = cc + GET(cc, 1); if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) { - common->localptrs[cc - common->start] = localptr; - localptr += sizeof(sljit_w); + common->private_data_ptrs[cc - common->start] = private_data_ptr; + private_data_ptr += sizeof(sljit_sw); } - cc += 1 + LINK_SIZE; + bracketlen = 1 + LINK_SIZE; break; + case OP_BRA: + bracketlen = 1 + LINK_SIZE; + break; + + case OP_CBRA: + case OP_SCBRA: + bracketlen = 1 + LINK_SIZE + IMM2_SIZE; + break; + + CASE_ITERATOR_PRIVATE_DATA_1 + space = 1; + size = -2; + break; + + CASE_ITERATOR_PRIVATE_DATA_2A + space = 2; + size = -2; + break; + + CASE_ITERATOR_PRIVATE_DATA_2B + space = 2; + size = -(2 + IMM2_SIZE); + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_1 + space = 1; + size = 1; + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_2A + if (cc[1] != OP_ANYNL && cc[1] != OP_EXTUNI) + space = 2; + size = 1; + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_2B + if (cc[1 + IMM2_SIZE] != OP_ANYNL && cc[1 + IMM2_SIZE] != OP_EXTUNI) + space = 2; + size = 1 + IMM2_SIZE; + break; + + case OP_CLASS: + case OP_NCLASS: + size += 1 + 32 / sizeof(pcre_uchar); + space = get_class_iterator_size(cc + size); + break; + +#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + case OP_XCLASS: + size = GET(cc, 1); + space = get_class_iterator_size(cc + size); + break; +#endif + default: cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); break; } + + /* Character iterators, which are not inside a repeated bracket, + gets a private slot instead of allocating it on the stack. */ + if (space > 0 && cc >= end) + { + common->private_data_ptrs[cc - common->start] = private_data_ptr; + private_data_ptr += sizeof(sljit_sw) * space; + } + + if (size != 0) + { + if (size < 0) + { + cc += -size; +#ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + } + else + cc += size; + } + + if (bracketlen > 0) + { + if (cc >= end) + { + end = bracketend(cc); + if (end[-1 - LINK_SIZE] == OP_KET) + end = NULL; + } + cc += bracketlen; + } } +*private_data_start = private_data_ptr; } -/* Returns with -1 if no need for frame. */ -static int get_framesize(compiler_common *common, pcre_uchar *cc, BOOL recursive) +/* Returns with a frame_types (always < 0) if no need for frame. */ +static int get_framesize(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, BOOL recursive, BOOL* needs_control_head) { -pcre_uchar *ccend = bracketend(cc); int length = 0; -BOOL possessive = FALSE; +int possessive = 0; +BOOL stack_restore = FALSE; BOOL setsom_found = recursive; BOOL setmark_found = recursive; +/* The last capture is a local variable even for recursions. */ +BOOL capture_last_found = FALSE; -if (!recursive && (*cc == OP_CBRAPOS || *cc == OP_SCBRAPOS)) +#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD +SLJIT_ASSERT(common->control_head_ptr != 0); +*needs_control_head = TRUE; +#else +*needs_control_head = FALSE; +#endif + +if (ccend == NULL) { - length = 3; - possessive = TRUE; + ccend = bracketend(cc) - (1 + LINK_SIZE); + if (!recursive && (*cc == OP_CBRAPOS || *cc == OP_SCBRAPOS)) + { + possessive = length = (common->capture_last_ptr != 0) ? 5 : 3; + /* This is correct regardless of common->capture_last_ptr. */ + capture_last_found = TRUE; + } + cc = next_opcode(common, cc); } -cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); while (cc < ccend) switch(*cc) { case OP_SET_SOM: SLJIT_ASSERT(common->has_set_som); + stack_restore = TRUE; if (!setsom_found) { length += 2; @@ -818,16 +1231,22 @@ while (cc < ccend) break; case OP_MARK: + case OP_PRUNE_ARG: + case OP_THEN_ARG: SLJIT_ASSERT(common->mark_ptr != 0); + stack_restore = TRUE; if (!setmark_found) { length += 2; setmark_found = TRUE; } + if (common->control_head_ptr != 0) + *needs_control_head = TRUE; cc += 1 + 2 + cc[1]; break; case OP_RECURSE: + stack_restore = TRUE; if (common->has_set_som && !setsom_found) { length += 2; @@ -838,6 +1257,11 @@ while (cc < ccend) length += 2; setmark_found = TRUE; } + if (common->capture_last_ptr != 0 && !capture_last_found) + { + length += 2; + capture_last_found = TRUE; + } cc += 1 + LINK_SIZE; break; @@ -845,31 +1269,105 @@ while (cc < ccend) case OP_CBRAPOS: case OP_SCBRA: case OP_SCBRAPOS: + stack_restore = TRUE; + if (common->capture_last_ptr != 0 && !capture_last_found) + { + length += 2; + capture_last_found = TRUE; + } length += 3; cc += 1 + LINK_SIZE + IMM2_SIZE; break; default: + stack_restore = TRUE; + /* Fall through. */ + + case OP_NOT_WORD_BOUNDARY: + case OP_WORD_BOUNDARY: + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + case OP_ANY: + case OP_ALLANY: + case OP_ANYBYTE: + case OP_NOTPROP: + case OP_PROP: + case OP_ANYNL: + case OP_NOT_HSPACE: + case OP_HSPACE: + case OP_NOT_VSPACE: + case OP_VSPACE: + case OP_EXTUNI: + case OP_EODN: + case OP_EOD: + case OP_CIRC: + case OP_CIRCM: + case OP_DOLL: + case OP_DOLLM: + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + + case OP_EXACT: + case OP_POSSTAR: + case OP_POSPLUS: + case OP_POSQUERY: + case OP_POSUPTO: + + case OP_EXACTI: + case OP_POSSTARI: + case OP_POSPLUSI: + case OP_POSQUERYI: + case OP_POSUPTOI: + + case OP_NOTEXACT: + case OP_NOTPOSSTAR: + case OP_NOTPOSPLUS: + case OP_NOTPOSQUERY: + case OP_NOTPOSUPTO: + + case OP_NOTEXACTI: + case OP_NOTPOSSTARI: + case OP_NOTPOSPLUSI: + case OP_NOTPOSQUERYI: + case OP_NOTPOSUPTOI: + + case OP_TYPEEXACT: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: + case OP_TYPEPOSUPTO: + + case OP_CLASS: + case OP_NCLASS: + case OP_XCLASS: + cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); break; } /* Possessive quantifiers can use a special case. */ -if (SLJIT_UNLIKELY(possessive) && length == 3) - return -1; +if (SLJIT_UNLIKELY(possessive == length)) + return stack_restore ? no_frame : no_stack; if (length > 0) return length + 1; -return -1; +return stack_restore ? no_frame : no_stack; } -static void init_frame(compiler_common *common, pcre_uchar *cc, int stackpos, int stacktop, BOOL recursive) +static void init_frame(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, int stackpos, int stacktop, BOOL recursive) { DEFINE_COMPILER; -pcre_uchar *ccend = bracketend(cc); BOOL setsom_found = recursive; BOOL setmark_found = recursive; +/* The last capture is a local variable even for recursions. */ +BOOL capture_last_found = FALSE; int offset; /* >= 1 + shortest item size (2) */ @@ -877,8 +1375,13 @@ SLJIT_UNUSED_ARG(stacktop); SLJIT_ASSERT(stackpos >= stacktop + 2); stackpos = STACK(stackpos); -if (recursive || (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS)) - cc = next_opcode(common, cc); +if (ccend == NULL) + { + ccend = bracketend(cc) - (1 + LINK_SIZE); + if (recursive || (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS)) + cc = next_opcode(common, cc); + } + SLJIT_ASSERT(cc != NULL); while (cc < ccend) switch(*cc) @@ -888,24 +1391,26 @@ while (cc < ccend) if (!setsom_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, frame_setstrbegin); - stackpos += (int)sizeof(sljit_w); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0)); + stackpos += (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_w); + stackpos += (int)sizeof(sljit_sw); setsom_found = TRUE; } cc += 1; break; case OP_MARK: + case OP_PRUNE_ARG: + case OP_THEN_ARG: SLJIT_ASSERT(common->mark_ptr != 0); if (!setmark_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, frame_setmark); - stackpos += (int)sizeof(sljit_w); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr); + stackpos += (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_w); + stackpos += (int)sizeof(sljit_sw); setmark_found = TRUE; } cc += 1 + 2 + cc[1]; @@ -915,21 +1420,30 @@ while (cc < ccend) if (common->has_set_som && !setsom_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, frame_setstrbegin); - stackpos += (int)sizeof(sljit_w); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0)); + stackpos += (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_w); + stackpos += (int)sizeof(sljit_sw); setsom_found = TRUE; } if (common->mark_ptr != 0 && !setmark_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, frame_setmark); - stackpos += (int)sizeof(sljit_w); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr); + stackpos += (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_w); + stackpos += (int)sizeof(sljit_sw); setmark_found = TRUE; } + if (common->capture_last_ptr != 0 && !capture_last_found) + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr); + stackpos += (int)sizeof(sljit_sw); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); + stackpos += (int)sizeof(sljit_sw); + capture_last_found = TRUE; + } cc += 1 + LINK_SIZE; break; @@ -937,15 +1451,24 @@ while (cc < ccend) case OP_CBRAPOS: case OP_SCBRA: case OP_SCBRAPOS: + if (common->capture_last_ptr != 0 && !capture_last_found) + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr); + stackpos += (int)sizeof(sljit_sw); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); + stackpos += (int)sizeof(sljit_sw); + capture_last_found = TRUE; + } offset = (GET2(cc, 1 + LINK_SIZE)) << 1; OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset)); - stackpos += (int)sizeof(sljit_w); + stackpos += (int)sizeof(sljit_sw); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); - stackpos += (int)sizeof(sljit_w); + stackpos += (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0); - stackpos += (int)sizeof(sljit_w); + stackpos += (int)sizeof(sljit_sw); cc += 1 + LINK_SIZE + IMM2_SIZE; break; @@ -956,19 +1479,27 @@ while (cc < ccend) break; } -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, frame_end); +OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, 0); SLJIT_ASSERT(stackpos == STACK(stacktop)); } -static SLJIT_INLINE int get_localsize(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend) +static SLJIT_INLINE int get_private_data_copy_length(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, BOOL needs_control_head) { -int localsize = 2; +int private_data_length = needs_control_head ? 3 : 2; +int size; pcre_uchar *alternative; -/* Calculate the sum of the local variables. */ +/* Calculate the sum of the private machine words. */ while (cc < ccend) { + size = 0; switch(*cc) { + case OP_KET: + if (PRIVATE_DATA(cc) != 0) + private_data_length++; + cc += 1 + LINK_SIZE; + break; + case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: @@ -979,19 +1510,20 @@ while (cc < ccend) case OP_SBRA: case OP_SBRAPOS: case OP_SCOND: - localsize++; + private_data_length++; cc += 1 + LINK_SIZE; break; case OP_CBRA: case OP_SCBRA: - localsize++; + if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) + private_data_length++; cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: - localsize += 2; + private_data_length += 2; cc += 1 + LINK_SIZE + IMM2_SIZE; break; @@ -999,10 +1531,68 @@ while (cc < ccend) /* Might be a hidden SCOND. */ alternative = cc + GET(cc, 1); if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) - localsize++; + private_data_length++; cc += 1 + LINK_SIZE; break; + CASE_ITERATOR_PRIVATE_DATA_1 + if (PRIVATE_DATA(cc)) + private_data_length++; + cc += 2; +#ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + CASE_ITERATOR_PRIVATE_DATA_2A + if (PRIVATE_DATA(cc)) + private_data_length += 2; + cc += 2; +#ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + CASE_ITERATOR_PRIVATE_DATA_2B + if (PRIVATE_DATA(cc)) + private_data_length += 2; + cc += 2 + IMM2_SIZE; +#ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_1 + if (PRIVATE_DATA(cc)) + private_data_length++; + cc += 1; + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_2A + if (PRIVATE_DATA(cc)) + private_data_length += 2; + cc += 1; + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_2B + if (PRIVATE_DATA(cc)) + private_data_length += 2; + cc += 1 + IMM2_SIZE; + break; + + case OP_CLASS: + case OP_NCLASS: +#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + case OP_XCLASS: + size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(pcre_uchar); +#else + size = 1 + 32 / (int)sizeof(pcre_uchar); +#endif + if (PRIVATE_DATA(cc)) + private_data_length += get_class_iterator_size(cc + size); + cc += size; + break; + default: cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); @@ -1010,15 +1600,15 @@ while (cc < ccend) } } SLJIT_ASSERT(cc == ccend); -return localsize; +return private_data_length; } -static void copy_locals(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, - BOOL save, int stackptr, int stacktop) +static void copy_private_data(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, + BOOL save, int stackptr, int stacktop, BOOL needs_control_head) { DEFINE_COMPILER; int srcw[2]; -int count; +int count, size; BOOL tmp1next = TRUE; BOOL tmp1empty = TRUE; BOOL tmp2empty = TRUE; @@ -1035,31 +1625,37 @@ stacktop = STACK(stacktop - 1); if (!save) { - stackptr += sizeof(sljit_w); + stackptr += (needs_control_head ? 2 : 1) * sizeof(sljit_sw); if (stackptr < stacktop) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), stackptr); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); tmp1empty = FALSE; } if (stackptr < stacktop) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), stackptr); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); tmp2empty = FALSE; } /* The tmp1next must be TRUE in either way. */ } -while (status != end) +do { count = 0; switch(status) { case start: - SLJIT_ASSERT(save && common->recursive_head != 0); + SLJIT_ASSERT(save && common->recursive_head_ptr != 0); count = 1; - srcw[0] = common->recursive_head; + srcw[0] = common->recursive_head_ptr; + if (needs_control_head) + { + SLJIT_ASSERT(common->control_head_ptr != 0); + count = 2; + srcw[1] = common->control_head_ptr; + } status = loop; break; @@ -1072,6 +1668,15 @@ while (status != end) switch(*cc) { + case OP_KET: + if (PRIVATE_DATA(cc) != 0) + { + count = 1; + srcw[0] = PRIVATE_DATA(cc); + } + cc += 1 + LINK_SIZE; + break; + case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: @@ -1083,24 +1688,27 @@ while (status != end) case OP_SBRAPOS: case OP_SCOND: count = 1; - srcw[0] = PRIV_DATA(cc); + srcw[0] = PRIVATE_DATA(cc); SLJIT_ASSERT(srcw[0] != 0); cc += 1 + LINK_SIZE; break; case OP_CBRA: case OP_SCBRA: - count = 1; - srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE)); + if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) + { + count = 1; + srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE)); + } cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: count = 2; + srcw[0] = PRIVATE_DATA(cc); srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE)); - srcw[0] = PRIV_DATA(cc); - SLJIT_ASSERT(srcw[0] != 0); + SLJIT_ASSERT(srcw[0] != 0 && srcw[1] != 0); cc += 1 + LINK_SIZE + IMM2_SIZE; break; @@ -1110,12 +1718,108 @@ while (status != end) if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) { count = 1; - srcw[0] = PRIV_DATA(cc); + srcw[0] = PRIVATE_DATA(cc); SLJIT_ASSERT(srcw[0] != 0); } cc += 1 + LINK_SIZE; break; + CASE_ITERATOR_PRIVATE_DATA_1 + if (PRIVATE_DATA(cc)) + { + count = 1; + srcw[0] = PRIVATE_DATA(cc); + } + cc += 2; +#ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + CASE_ITERATOR_PRIVATE_DATA_2A + if (PRIVATE_DATA(cc)) + { + count = 2; + srcw[0] = PRIVATE_DATA(cc); + srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw); + } + cc += 2; +#ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + CASE_ITERATOR_PRIVATE_DATA_2B + if (PRIVATE_DATA(cc)) + { + count = 2; + srcw[0] = PRIVATE_DATA(cc); + srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw); + } + cc += 2 + IMM2_SIZE; +#ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); +#endif + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_1 + if (PRIVATE_DATA(cc)) + { + count = 1; + srcw[0] = PRIVATE_DATA(cc); + } + cc += 1; + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_2A + if (PRIVATE_DATA(cc)) + { + count = 2; + srcw[0] = PRIVATE_DATA(cc); + srcw[1] = srcw[0] + sizeof(sljit_sw); + } + cc += 1; + break; + + CASE_ITERATOR_TYPE_PRIVATE_DATA_2B + if (PRIVATE_DATA(cc)) + { + count = 2; + srcw[0] = PRIVATE_DATA(cc); + srcw[1] = srcw[0] + sizeof(sljit_sw); + } + cc += 1 + IMM2_SIZE; + break; + + case OP_CLASS: + case OP_NCLASS: +#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + case OP_XCLASS: + size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(pcre_uchar); +#else + size = 1 + 32 / (int)sizeof(pcre_uchar); +#endif + if (PRIVATE_DATA(cc)) + switch(get_class_iterator_size(cc + size)) + { + case 1: + count = 1; + srcw[0] = PRIVATE_DATA(cc); + break; + + case 2: + count = 2; + srcw[0] = PRIVATE_DATA(cc); + srcw[1] = srcw[0] + sizeof(sljit_sw); + break; + + default: + SLJIT_ASSERT_STOP(); + break; + } + cc += size; + break; + default: cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); @@ -1138,7 +1842,7 @@ while (status != end) if (!tmp1empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); } OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), srcw[count]); tmp1empty = FALSE; @@ -1149,7 +1853,7 @@ while (status != end) if (!tmp2empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); } OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), srcw[count]); tmp2empty = FALSE; @@ -1166,7 +1870,7 @@ while (status != end) if (!tmp1empty) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), stackptr); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); } tmp1next = FALSE; } @@ -1178,13 +1882,14 @@ while (status != end) if (!tmp2empty) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), stackptr); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); } tmp1next = TRUE; } } } } +while (status != end); if (save) { @@ -1193,12 +1898,12 @@ if (save) if (!tmp1empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); } if (!tmp2empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); } } else @@ -1206,19 +1911,59 @@ if (save) if (!tmp2empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); } if (!tmp1empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0); - stackptr += sizeof(sljit_w); + stackptr += sizeof(sljit_sw); } } } SLJIT_ASSERT(cc == ccend && stackptr == stacktop && (save || (tmp1empty && tmp2empty))); } -static SLJIT_INLINE BOOL ispowerof2(unsigned int value) +static SLJIT_INLINE pcre_uchar *set_then_offsets(compiler_common *common, pcre_uchar *cc, pcre_uint8 *current_offset) +{ +pcre_uchar *end = bracketend(cc); +BOOL has_alternatives = cc[GET(cc, 1)] == OP_ALT; + +/* Assert captures then. */ +if (*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) + current_offset = NULL; +/* Conditional block does not. */ +if (*cc == OP_COND || *cc == OP_SCOND) + has_alternatives = FALSE; + +cc = next_opcode(common, cc); +if (has_alternatives) + current_offset = common->then_offsets + (cc - common->start); + +while (cc < end) + { + if ((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND)) + cc = set_then_offsets(common, cc, current_offset); + else + { + if (*cc == OP_ALT && has_alternatives) + current_offset = common->then_offsets + (cc + 1 + LINK_SIZE - common->start); + if (*cc >= OP_THEN && *cc <= OP_THEN_ARG && current_offset != NULL) + *current_offset = 1; + cc = next_opcode(common, cc); + } + } + +return end; +} + +#undef CASE_ITERATOR_PRIVATE_DATA_1 +#undef CASE_ITERATOR_PRIVATE_DATA_2A +#undef CASE_ITERATOR_PRIVATE_DATA_2B +#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_1 +#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2A +#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2B + +static SLJIT_INLINE BOOL is_powerof2(unsigned int value) { return (value & (value - 1)) == 0; } @@ -1228,8 +1973,8 @@ static SLJIT_INLINE void set_jumps(jump_list *list, struct sljit_label *label) while (list) { /* sljit_set_label is clever enough to do nothing - if either the jump or the label is NULL */ - sljit_set_label(list->jump, label); + if either the jump or the label is NULL. */ + SET_LABEL(list->jump, label); list = list->next; } } @@ -1245,17 +1990,15 @@ if (list_item) } } -static void add_stub(compiler_common *common, enum stub_types type, int data, struct sljit_jump *start) +static void add_stub(compiler_common *common, struct sljit_jump *start) { DEFINE_COMPILER; stub_list* list_item = sljit_alloc_memory(compiler, sizeof(stub_list)); if (list_item) { - list_item->type = type; - list_item->data = data; list_item->start = start; - list_item->leave = LABEL(); + list_item->quit = LABEL(); list_item->next = common->stubs; common->stubs = list_item; } @@ -1269,23 +2012,18 @@ stub_list* list_item = common->stubs; while (list_item) { JUMPHERE(list_item->start); - switch(list_item->type) - { - case stack_alloc: - add_jump(compiler, &common->stackalloc, JUMP(SLJIT_FAST_CALL)); - break; - } - JUMPTO(SLJIT_JUMP, list_item->leave); + add_jump(compiler, &common->stackalloc, JUMP(SLJIT_FAST_CALL)); + JUMPTO(SLJIT_JUMP, list_item->quit); list_item = list_item->next; } common->stubs = NULL; } -static SLJIT_INLINE void decrease_call_count(compiler_common *common) +static SLJIT_INLINE void count_match(compiler_common *common) { DEFINE_COMPILER; -OP2(SLJIT_SUB | SLJIT_SET_E, CALL_COUNT, 0, CALL_COUNT, 0, SLJIT_IMM, 1); +OP2(SLJIT_SUB | SLJIT_SET_E, COUNT_MATCH, 0, COUNT_MATCH, 0, SLJIT_IMM, 1); add_jump(compiler, &common->calllimit, JUMP(SLJIT_C_ZERO)); } @@ -1294,7 +2032,7 @@ static SLJIT_INLINE void allocate_stack(compiler_common *common, int size) /* May destroy all locals and registers except TMP2. */ DEFINE_COMPILER; -OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_w)); +OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); #ifdef DESTROY_REGISTERS OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345); OP1(SLJIT_MOV, TMP3, 0, TMP1, 0); @@ -1302,13 +2040,13 @@ OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, TMP1, 0); #endif -add_stub(common, stack_alloc, 0, CMP(SLJIT_C_GREATER, STACK_TOP, 0, STACK_LIMIT, 0)); +add_stub(common, CMP(SLJIT_C_GREATER, STACK_TOP, 0, STACK_LIMIT, 0)); } static SLJIT_INLINE void free_stack(compiler_common *common, int size) { DEFINE_COMPILER; -OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_w)); +OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); } static SLJIT_INLINE void reset_ovector(compiler_common *common, int length) @@ -1316,104 +2054,175 @@ static SLJIT_INLINE void reset_ovector(compiler_common *common, int length) DEFINE_COMPILER; struct sljit_label *loop; int i; + /* At this point we can freely use all temporary registers. */ +SLJIT_ASSERT(length > 1); /* TMP1 returns with begin - 1. */ -OP2(SLJIT_SUB, SLJIT_TEMPORARY_REG1, 0, SLJIT_MEM1(SLJIT_SAVED_REG1), SLJIT_OFFSETOF(jit_arguments, begin), SLJIT_IMM, IN_UCHARS(1)); +OP2(SLJIT_SUB, SLJIT_SCRATCH_REG1, 0, SLJIT_MEM1(SLJIT_SAVED_REG1), SLJIT_OFFSETOF(jit_arguments, begin), SLJIT_IMM, IN_UCHARS(1)); if (length < 8) { - for (i = 0; i < length; i++) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(i), SLJIT_TEMPORARY_REG1, 0); + for (i = 1; i < length; i++) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(i), SLJIT_SCRATCH_REG1, 0); } else { - GET_LOCAL_BASE(SLJIT_TEMPORARY_REG2, 0, OVECTOR_START - sizeof(sljit_w)); - OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, length); + GET_LOCAL_BASE(SLJIT_SCRATCH_REG2, 0, OVECTOR_START); + OP1(SLJIT_MOV, SLJIT_SCRATCH_REG3, 0, SLJIT_IMM, length - 1); loop = LABEL(); - OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), sizeof(sljit_w), SLJIT_TEMPORARY_REG1, 0); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_TEMPORARY_REG3, 0, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, 1); + OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_SCRATCH_REG2), sizeof(sljit_sw), SLJIT_SCRATCH_REG1, 0); + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_SCRATCH_REG3, 0, SLJIT_SCRATCH_REG3, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_C_NOT_ZERO, loop); } } +static SLJIT_INLINE void do_reset_match(compiler_common *common, int length) +{ +DEFINE_COMPILER; +struct sljit_label *loop; +int i; + +SLJIT_ASSERT(length > 1); +/* OVECTOR(1) contains the "string begin - 1" constant. */ +if (length > 2) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1)); +if (length < 8) + { + for (i = 2; i < length; i++) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(i), TMP1, 0); + } +else + { + GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + sizeof(sljit_sw)); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2); + loop = LABEL(); + OP1(SLJIT_MOVU, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0); + OP2(SLJIT_SUB | SLJIT_SET_E, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); + JUMPTO(SLJIT_C_NOT_ZERO, loop); + } + +OP1(SLJIT_MOV, STACK_TOP, 0, ARGUMENTS, 0); +if (common->mark_ptr != 0) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr, SLJIT_IMM, 0); +if (common->control_head_ptr != 0) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_IMM, 0); +OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(jit_arguments, stack)); +OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_ptr); +OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, base)); +} + +static sljit_sw SLJIT_CALL do_search_mark(sljit_sw *current, const pcre_uchar *skip_arg) +{ +while (current != NULL) + { + switch (current[-2]) + { + case type_then_trap: + break; + + case type_mark: + if (STRCMP_UC_UC(skip_arg, (pcre_uchar *)current[-3]) == 0) + return current[-4]; + break; + + default: + SLJIT_ASSERT_STOP(); + break; + } + current = (sljit_sw*)current[-1]; + } +return -1; +} + static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket) { DEFINE_COMPILER; struct sljit_label *loop; -struct sljit_jump *earlyexit; +struct sljit_jump *early_quit; /* At this point we can freely use all registers. */ OP1(SLJIT_MOV, SLJIT_SAVED_REG3, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1), STR_PTR, 0); -OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG1, 0, ARGUMENTS, 0); +OP1(SLJIT_MOV, SLJIT_SCRATCH_REG1, 0, ARGUMENTS, 0); if (common->mark_ptr != 0) - OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG3, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr); -OP1(SLJIT_MOV_SI, SLJIT_TEMPORARY_REG2, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG1), SLJIT_OFFSETOF(jit_arguments, offsetcount)); + OP1(SLJIT_MOV, SLJIT_SCRATCH_REG3, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr); +OP1(SLJIT_MOV_SI, SLJIT_SCRATCH_REG2, 0, SLJIT_MEM1(SLJIT_SCRATCH_REG1), SLJIT_OFFSETOF(jit_arguments, offset_count)); if (common->mark_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_TEMPORARY_REG1), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_TEMPORARY_REG3, 0); -OP2(SLJIT_SUB, SLJIT_TEMPORARY_REG3, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG1), SLJIT_OFFSETOF(jit_arguments, offsets), SLJIT_IMM, sizeof(int)); -OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG1, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG1), SLJIT_OFFSETOF(jit_arguments, begin)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SCRATCH_REG1), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_SCRATCH_REG3, 0); +OP2(SLJIT_SUB, SLJIT_SCRATCH_REG3, 0, SLJIT_MEM1(SLJIT_SCRATCH_REG1), SLJIT_OFFSETOF(jit_arguments, offsets), SLJIT_IMM, sizeof(int)); +OP1(SLJIT_MOV, SLJIT_SCRATCH_REG1, 0, SLJIT_MEM1(SLJIT_SCRATCH_REG1), SLJIT_OFFSETOF(jit_arguments, begin)); GET_LOCAL_BASE(SLJIT_SAVED_REG1, 0, OVECTOR_START); /* Unlikely, but possible */ -earlyexit = CMP(SLJIT_C_EQUAL, SLJIT_TEMPORARY_REG2, 0, SLJIT_IMM, 0); +early_quit = CMP(SLJIT_C_EQUAL, SLJIT_SCRATCH_REG2, 0, SLJIT_IMM, 0); loop = LABEL(); -OP2(SLJIT_SUB, SLJIT_SAVED_REG2, 0, SLJIT_MEM1(SLJIT_SAVED_REG1), 0, SLJIT_TEMPORARY_REG1, 0); -OP2(SLJIT_ADD, SLJIT_SAVED_REG1, 0, SLJIT_SAVED_REG1, 0, SLJIT_IMM, sizeof(sljit_w)); +OP2(SLJIT_SUB, SLJIT_SAVED_REG2, 0, SLJIT_MEM1(SLJIT_SAVED_REG1), 0, SLJIT_SCRATCH_REG1, 0); +OP2(SLJIT_ADD, SLJIT_SAVED_REG1, 0, SLJIT_SAVED_REG1, 0, SLJIT_IMM, sizeof(sljit_sw)); /* Copy the integer value to the output buffer */ -#ifdef COMPILE_PCRE16 -OP2(SLJIT_ASHR, SLJIT_SAVED_REG2, 0, SLJIT_SAVED_REG2, 0, SLJIT_IMM, 1); +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 +OP2(SLJIT_ASHR, SLJIT_SAVED_REG2, 0, SLJIT_SAVED_REG2, 0, SLJIT_IMM, UCHAR_SHIFT); #endif -OP1(SLJIT_MOVU_SI, SLJIT_MEM1(SLJIT_TEMPORARY_REG3), sizeof(int), SLJIT_SAVED_REG2, 0); -OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_TEMPORARY_REG2, 0, SLJIT_TEMPORARY_REG2, 0, SLJIT_IMM, 1); +OP1(SLJIT_MOVU_SI, SLJIT_MEM1(SLJIT_SCRATCH_REG3), sizeof(int), SLJIT_SAVED_REG2, 0); +OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_SCRATCH_REG2, 0, SLJIT_SCRATCH_REG2, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_C_NOT_ZERO, loop); -JUMPHERE(earlyexit); +JUMPHERE(early_quit); /* Calculate the return value, which is the maximum ovector value. */ if (topbracket > 1) { - GET_LOCAL_BASE(SLJIT_TEMPORARY_REG1, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_w)); - OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG2, 0, SLJIT_IMM, topbracket + 1); + GET_LOCAL_BASE(SLJIT_SCRATCH_REG1, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_SCRATCH_REG2, 0, SLJIT_IMM, topbracket + 1); /* OVECTOR(0) is never equal to SLJIT_SAVED_REG3. */ loop = LABEL(); - OP1(SLJIT_MOVU, SLJIT_TEMPORARY_REG3, 0, SLJIT_MEM1(SLJIT_TEMPORARY_REG1), -(2 * (sljit_w)sizeof(sljit_w))); - OP2(SLJIT_SUB, SLJIT_TEMPORARY_REG2, 0, SLJIT_TEMPORARY_REG2, 0, SLJIT_IMM, 1); - CMPTO(SLJIT_C_EQUAL, SLJIT_TEMPORARY_REG3, 0, SLJIT_SAVED_REG3, 0, loop); - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_TEMPORARY_REG2, 0); + OP1(SLJIT_MOVU, SLJIT_SCRATCH_REG3, 0, SLJIT_MEM1(SLJIT_SCRATCH_REG1), -(2 * (sljit_sw)sizeof(sljit_sw))); + OP2(SLJIT_SUB, SLJIT_SCRATCH_REG2, 0, SLJIT_SCRATCH_REG2, 0, SLJIT_IMM, 1); + CMPTO(SLJIT_C_EQUAL, SLJIT_SCRATCH_REG3, 0, SLJIT_SAVED_REG3, 0, loop); + OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_SCRATCH_REG2, 0); } else 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) +static SLJIT_INLINE void return_with_partial_match(compiler_common *common, struct sljit_label *quit) { DEFINE_COMPILER; +struct sljit_jump *jump; SLJIT_COMPILE_ASSERT(STR_END == SLJIT_SAVED_REG2, str_end_must_be_saved_reg2); -SLJIT_ASSERT(common->start_used_ptr != 0 && (common->mode == JIT_PARTIAL_SOFT_COMPILE ? common->hit_start != 0 : common->hit_start == 0)); +SLJIT_ASSERT(common->start_used_ptr != 0 && common->start_ptr != 0 + && (common->mode == JIT_PARTIAL_SOFT_COMPILE ? common->hit_start != 0 : common->hit_start == 0)); -OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG2, 0, ARGUMENTS, 0); +OP1(SLJIT_MOV, SLJIT_SCRATCH_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); +OP1(SLJIT_MOV_SI, SLJIT_SCRATCH_REG3, 0, SLJIT_MEM1(SLJIT_SCRATCH_REG2), SLJIT_OFFSETOF(jit_arguments, real_offset_count)); +CMPTO(SLJIT_C_SIG_LESS, SLJIT_SCRATCH_REG3, 0, SLJIT_IMM, 2, quit); /* 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 ? common->start_used_ptr : common->hit_start); +OP1(SLJIT_MOV, SLJIT_SAVED_REG1, 0, SLJIT_MEM1(SLJIT_SCRATCH_REG2), SLJIT_OFFSETOF(jit_arguments, begin)); +OP1(SLJIT_MOV, SLJIT_SCRATCH_REG2, 0, SLJIT_MEM1(SLJIT_SCRATCH_REG2), SLJIT_OFFSETOF(jit_arguments, offsets)); + +jump = CMP(SLJIT_C_SIG_LESS, SLJIT_SCRATCH_REG3, 0, SLJIT_IMM, 3); +OP2(SLJIT_SUB, SLJIT_SCRATCH_REG3, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mode == JIT_PARTIAL_HARD_COMPILE ? common->start_ptr : (common->hit_start + (int)sizeof(sljit_sw)), SLJIT_SAVED_REG1, 0); +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 +OP2(SLJIT_ASHR, SLJIT_SCRATCH_REG3, 0, SLJIT_SCRATCH_REG3, 0, SLJIT_IMM, UCHAR_SHIFT); +#endif +OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_SCRATCH_REG2), 2 * sizeof(int), SLJIT_SCRATCH_REG3, 0); +JUMPHERE(jump); + +OP1(SLJIT_MOV, SLJIT_SCRATCH_REG3, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mode == JIT_PARTIAL_HARD_COMPILE ? common->start_used_ptr : common->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); +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 +OP2(SLJIT_ASHR, SLJIT_SAVED_REG2, 0, SLJIT_SAVED_REG2, 0, SLJIT_IMM, UCHAR_SHIFT); #endif -OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), sizeof(int), SLJIT_SAVED_REG2, 0); +OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_SCRATCH_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); +OP2(SLJIT_SUB, SLJIT_SCRATCH_REG3, 0, SLJIT_SCRATCH_REG3, 0, SLJIT_SAVED_REG1, 0); +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 +OP2(SLJIT_ASHR, SLJIT_SCRATCH_REG3, 0, SLJIT_SCRATCH_REG3, 0, SLJIT_IMM, UCHAR_SHIFT); #endif -OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), 0, SLJIT_TEMPORARY_REG3, 0); +OP1(SLJIT_MOV_SI, SLJIT_MEM1(SLJIT_SCRATCH_REG2), 0, SLJIT_SCRATCH_REG3, 0); -JUMPTO(SLJIT_JUMP, leave); +JUMPTO(SLJIT_JUMP, quit); } static SLJIT_INLINE void check_start_used_ptr(compiler_common *common) @@ -1524,10 +2333,10 @@ if (c <= 127 && bit == 0x20) return (0 << 8) | 0x20; /* Since c != oc, they must have at least 1 bit difference. */ -if (!ispowerof2(bit)) +if (!is_powerof2(bit)) return 0; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 #ifdef SUPPORT_UTF if (common->utf && c > 127) @@ -1543,9 +2352,8 @@ if (common->utf && c > 127) #endif /* SUPPORT_UTF */ return (0 << 8) | bit; -#else /* COMPILE_PCRE8 */ +#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 -#ifdef COMPILE_PCRE16 #ifdef SUPPORT_UTF if (common->utf && c > 65535) { @@ -1556,14 +2364,13 @@ if (common->utf && c > 65535) } #endif /* SUPPORT_UTF */ return (bit < 256) ? ((0 << 8) | bit) : ((1 << 8) | (bit >> 8)); -#endif /* COMPILE_PCRE16 */ -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE[8|16|32] */ } static void check_partial(compiler_common *common, BOOL force) { -/* Checks whether a partial matching is occured. Does not modify registers. */ +/* Checks whether a partial matching is occurred. Does not modify registers. */ DEFINE_COMPILER; struct sljit_jump *jump = NULL; @@ -1578,7 +2385,7 @@ else if (common->mode == JIT_PARTIAL_SOFT_COMPILE) jump = CMP(SLJIT_C_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_used_ptr, SLJIT_IMM, -1); if (common->mode == JIT_PARTIAL_SOFT_COMPILE) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, -1); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, 0); else { if (common->partialmatchlabel != NULL) @@ -1591,35 +2398,34 @@ if (jump != NULL) JUMPHERE(jump); } -static struct sljit_jump *check_str_end(compiler_common *common) +static void check_str_end(compiler_common *common, jump_list **end_reached) { /* 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); + { + add_jump(compiler, end_reached, CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); + return; + } 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), common->start_used_ptr, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, -1); - JUMPHERE(nohit); - return_value = JUMP(SLJIT_JUMP); + add_jump(compiler, end_reached, CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_used_ptr, STR_PTR, 0)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, 0); + add_jump(compiler, end_reached, JUMP(SLJIT_JUMP)); } else { - return_value = CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_used_ptr, STR_PTR, 0); + add_jump(compiler, end_reached, CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->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 detect_partial_match(compiler_common *common, jump_list **backtracks) @@ -1638,7 +2444,7 @@ jump = CMP(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0); add_jump(compiler, backtracks, CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_used_ptr, STR_PTR, 0)); if (common->mode == JIT_PARTIAL_SOFT_COMPILE) { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, -1); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, 0); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); } else @@ -1656,25 +2462,23 @@ static void read_char(compiler_common *common) /* Reads the character into TMP1, updates STR_PTR. Does not check STR_END. TMP2 Destroyed. */ DEFINE_COMPILER; -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 struct sljit_jump *jump; #endif OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf) { -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 jump = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0); -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 jump = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xd800); -#endif -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE[8|16] */ add_jump(compiler, &common->utfreadchar, JUMP(SLJIT_FAST_CALL)); JUMPHERE(jump); } -#endif +#endif /* SUPPORT_UTF && !COMPILE_PCRE32 */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } @@ -1683,33 +2487,31 @@ static void peek_char(compiler_common *common) /* Reads the character into TMP1, keeps STR_PTR. Does not check STR_END. TMP2 Destroyed. */ DEFINE_COMPILER; -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 struct sljit_jump *jump; #endif OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf) { -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 jump = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0); -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 jump = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xd800); -#endif -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE[8|16] */ add_jump(compiler, &common->utfreadchar, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); JUMPHERE(jump); } -#endif +#endif /* SUPPORT_UTF && !COMPILE_PCRE32 */ } static void read_char8_type(compiler_common *common) { /* Reads the character type into TMP1, updates STR_PTR. Does not check STR_END. */ DEFINE_COMPILER; -#if defined SUPPORT_UTF || defined COMPILE_PCRE16 +#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 struct sljit_jump *jump; #endif @@ -1718,15 +2520,14 @@ if (common->utf) { OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 /* This can be an extra read in some situations, but hopefully it is needed in most cases. */ OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); jump = CMP(SLJIT_C_LESS, TMP2, 0, SLJIT_IMM, 0xc0); add_jump(compiler, &common->utfreadtype8, JUMP(SLJIT_FAST_CALL)); JUMPHERE(jump); -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); jump = CMP(SLJIT_C_GREATER, TMP2, 0, SLJIT_IMM, 255); OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); @@ -1734,23 +2535,27 @@ if (common->utf) /* Skip low surrogate if necessary. */ OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xfc00); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0xd800); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); -#endif -#endif /* COMPILE_PCRE8 */ +#elif defined COMPILE_PCRE32 + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); + jump = CMP(SLJIT_C_GREATER, TMP2, 0, SLJIT_IMM, 255); + OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); + JUMPHERE(jump); +#endif /* COMPILE_PCRE[8|16|32] */ return; } -#endif +#endif /* SUPPORT_UTF */ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#ifdef COMPILE_PCRE16 +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 /* The ctypes array contains only 256 values. */ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); jump = CMP(SLJIT_C_GREATER, TMP2, 0, SLJIT_IMM, 255); #endif OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); -#ifdef COMPILE_PCRE16 +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 JUMPHERE(jump); #endif } @@ -1759,7 +2564,8 @@ static void skip_char_back(compiler_common *common) { /* Goes one character back. Affects STR_PTR and TMP1. Does not check begin. */ DEFINE_COMPILER; -#if defined SUPPORT_UTF && defined COMPILE_PCRE8 +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 +#if defined COMPILE_PCRE8 struct sljit_label *label; if (common->utf) @@ -1771,8 +2577,7 @@ if (common->utf) CMPTO(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, label); return; } -#endif -#if defined SUPPORT_UTF && defined COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 if (common->utf) { OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1)); @@ -1780,12 +2585,13 @@ if (common->utf) /* Skip low surrogate if necessary. */ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xdc00); - COND_VALUE(SLJIT_MOV, TMP1, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0); return; } -#endif +#endif /* COMPILE_PCRE[8|16] */ +#endif /* SUPPORT_UTF && !COMPILE_PCRE32 */ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } @@ -1802,9 +2608,9 @@ if (nltype == NLTYPE_ANY) else if (nltype == NLTYPE_ANYCRLF) { OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_CR); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); add_jump(compiler, backtracks, JUMP(jumpiftrue ? SLJIT_C_NOT_ZERO : SLJIT_C_ZERO)); } else @@ -1816,7 +2622,7 @@ else #ifdef SUPPORT_UTF -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 static void do_utfreadchar(compiler_common *common) { /* Fast decoding a UTF-8 character. TMP1 contains the first byte @@ -1904,15 +2710,14 @@ sljit_emit_fast_return(compiler, RETURN_ADDR, 0); JUMPHERE(jump); /* We only have types for characters less than 256. */ -OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), (sljit_w)PRIV(utf8_table4) - 0xc0); +OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } -#else /* COMPILE_PCRE8 */ +#elif defined COMPILE_PCRE16 -#ifdef COMPILE_PCRE16 static void do_utfreadchar(compiler_common *common) { /* Fast decoding a UTF-16 character. TMP1 contains the first 16 bit char @@ -1937,9 +2742,8 @@ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } -#endif /* COMPILE_PCRE16 */ -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE[8|16] */ #endif /* SUPPORT_UTF */ @@ -1959,13 +2763,13 @@ SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 8); sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); -OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_w)PRIV(ucd_stage1)); +OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_w)PRIV(ucd_stage2)); +OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2)); OP1(SLJIT_MOV_UH, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_w)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype)); +OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype)); OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } @@ -1979,7 +2783,7 @@ struct sljit_label *newlinelabel = NULL; struct sljit_jump *start; struct sljit_jump *end = NULL; struct sljit_jump *nl = NULL; -#ifdef SUPPORT_UTF +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 struct sljit_jump *singlechar; #endif jump_list *newline = NULL; @@ -1994,8 +2798,7 @@ if (firstline) { /* Search for the end of the first line. */ SLJIT_ASSERT(common->first_line_end != 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end, STR_END, 0); + OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); if (common->nltype == NLTYPE_FIXED && common->newline > 255) { @@ -2006,6 +2809,7 @@ if (firstline) OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, mainloop); CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, mainloop); + JUMPHERE(end); OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } else @@ -2017,12 +2821,12 @@ if (firstline) read_char(common); check_newlinechar(common, common->nltype, &newline, TRUE); CMPTO(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0, mainloop); + JUMPHERE(end); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end, STR_PTR, 0); set_jumps(newline, LABEL()); } - JUMPHERE(end); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0); + OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); } start = JUMP(SLJIT_JUMP); @@ -2034,9 +2838,9 @@ if (newlinecheck) end = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff); - COND_VALUE(SLJIT_MOV, TMP1, 0, SLJIT_C_EQUAL); -#ifdef COMPILE_PCRE16 - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); nl = JUMP(SLJIT_JUMP); @@ -2057,27 +2861,28 @@ if (newlinecheck) CMPTO(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, newlinelabel); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#if defined SUPPORT_UTF && defined COMPILE_PCRE8 +#if defined SUPPORT_UTF && !defined COMPILE_PCRE32 +#if defined COMPILE_PCRE8 if (common->utf) { singlechar = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0); - OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)PRIV(utf8_table4) - 0xc0); + OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); JUMPHERE(singlechar); } -#endif -#if defined SUPPORT_UTF && defined COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 if (common->utf) { singlechar = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xd800); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); - COND_VALUE(SLJIT_MOV, TMP1, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); JUMPHERE(singlechar); } -#endif +#endif /* COMPILE_PCRE[8|16] */ +#endif /* SUPPORT_UTF && !COMPILE_PCRE32 */ JUMPHERE(start); if (newlinecheck) @@ -2089,22 +2894,192 @@ if (newlinecheck) return mainloop; } +#define MAX_N_CHARS 3 + +static SLJIT_INLINE BOOL fast_forward_first_n_chars(compiler_common *common, BOOL firstline) +{ +DEFINE_COMPILER; +struct sljit_label *start; +struct sljit_jump *quit; +pcre_uint32 chars[MAX_N_CHARS * 2]; +pcre_uchar *cc = common->start + 1 + LINK_SIZE; +int location = 0; +pcre_int32 len, c, bit, caseless; +int must_stop; + +/* We do not support alternatives now. */ +if (*(common->start + GET(common->start, 1)) == OP_ALT) + return FALSE; + +while (TRUE) + { + caseless = 0; + must_stop = 1; + switch(*cc) + { + case OP_CHAR: + must_stop = 0; + cc++; + break; + + case OP_CHARI: + caseless = 1; + must_stop = 0; + cc++; + break; + + case OP_SOD: + case OP_SOM: + case OP_SET_SOM: + case OP_NOT_WORD_BOUNDARY: + case OP_WORD_BOUNDARY: + case OP_EODN: + case OP_EOD: + case OP_CIRC: + case OP_CIRCM: + case OP_DOLL: + case OP_DOLLM: + /* Zero width assertions. */ + cc++; + continue; + + case OP_PLUS: + case OP_MINPLUS: + case OP_POSPLUS: + cc++; + break; + + case OP_EXACT: + cc += 1 + IMM2_SIZE; + break; + + case OP_PLUSI: + case OP_MINPLUSI: + case OP_POSPLUSI: + caseless = 1; + cc++; + break; + + case OP_EXACTI: + caseless = 1; + cc += 1 + IMM2_SIZE; + break; + + default: + must_stop = 2; + break; + } + + if (must_stop == 2) + break; + + len = 1; +#ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(cc[0])) len += GET_EXTRALEN(cc[0]); +#endif + + if (caseless && char_has_othercase(common, cc)) + { + caseless = char_get_othercase_bit(common, cc); + if (caseless == 0) + return FALSE; +#ifdef COMPILE_PCRE8 + caseless = ((caseless & 0xff) << 8) | (len - (caseless >> 8)); +#else + if ((caseless & 0x100) != 0) + caseless = ((caseless & 0xff) << 16) | (len - (caseless >> 9)); + else + caseless = ((caseless & 0xff) << 8) | (len - (caseless >> 9)); +#endif + } + else + caseless = 0; + + while (len > 0 && location < MAX_N_CHARS * 2) + { + c = *cc; + bit = 0; + if (len == (caseless & 0xff)) + { + bit = caseless >> 8; + c |= bit; + } + + chars[location] = c; + chars[location + 1] = bit; + + len--; + location += 2; + cc++; + } + + if (location >= MAX_N_CHARS * 2 || must_stop != 0) + break; + } + +/* At least two characters are required. */ +if (location < 2 * 2) + return FALSE; + +if (firstline) + { + SLJIT_ASSERT(common->first_line_end != 0); + OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); + OP2(SLJIT_SUB, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end, SLJIT_IMM, IN_UCHARS((location >> 1) - 1)); + } +else + OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS((location >> 1) - 1)); + +start = LABEL(); +quit = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); + +OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); +OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); +OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); +if (chars[1] != 0) + OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, chars[1]); +CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[0], start); +if (location > 2 * 2) + OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); +if (chars[3] != 0) + OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, chars[3]); +CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, chars[2], start); +if (location > 2 * 2) + { + if (chars[5] != 0) + OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, chars[5]); + CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[4], start); + } +OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); + +JUMPHERE(quit); + +if (firstline) + OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); +else + OP2(SLJIT_ADD, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS((location >> 1) - 1)); +return TRUE; +} + +#undef MAX_N_CHARS + static SLJIT_INLINE void fast_forward_first_char(compiler_common *common, pcre_uchar first_char, BOOL caseless, BOOL firstline) { DEFINE_COMPILER; struct sljit_label *start; -struct sljit_jump *leave; +struct sljit_jump *quit; struct sljit_jump *found; pcre_uchar oc, bit; if (firstline) { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, STR_END, 0); + SLJIT_ASSERT(common->first_line_end != 0); + OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end); } start = LABEL(); -leave = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); +quit = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); oc = first_char; @@ -2121,7 +3096,7 @@ if (first_char == oc) else { bit = first_char ^ oc; - if (ispowerof2(bit)) + if (is_powerof2(bit)) { OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, bit); found = CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, first_char | bit); @@ -2129,39 +3104,20 @@ else else { OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, first_char); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, oc); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); found = JUMP(SLJIT_C_NOT_ZERO); } } OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#if defined SUPPORT_UTF && defined COMPILE_PCRE8 -if (common->utf) - { - CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0, start); - OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)PRIV(utf8_table4) - 0xc0); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - } -#endif -#if defined SUPPORT_UTF && defined COMPILE_PCRE16 -if (common->utf) - { - CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xd800, start); - OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); - OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); - COND_VALUE(SLJIT_MOV, TMP1, 0, SLJIT_C_EQUAL); - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); - } -#endif JUMPTO(SLJIT_JUMP, start); JUMPHERE(found); -JUMPHERE(leave); +JUMPHERE(quit); if (firstline) - OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0); + OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); } static SLJIT_INLINE void fast_forward_newline(compiler_common *common, BOOL firstline) @@ -2170,14 +3126,15 @@ DEFINE_COMPILER; struct sljit_label *loop; struct sljit_jump *lastchar; struct sljit_jump *firstchar; -struct sljit_jump *leave; +struct sljit_jump *quit; struct sljit_jump *foundcr = NULL; struct sljit_jump *notfoundnl; jump_list *newline = NULL; if (firstline) { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, STR_END, 0); + SLJIT_ASSERT(common->first_line_end != 0); + OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end); } @@ -2191,21 +3148,21 @@ if (common->nltype == NLTYPE_FIXED && common->newline > 255) OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(2)); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_GREATER_EQUAL); -#ifdef COMPILE_PCRE16 - OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_GREATER_EQUAL); +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); loop = LABEL(); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - leave = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); + quit = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, loop); CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, loop); - JUMPHERE(leave); + JUMPHERE(quit); JUMPHERE(firstchar); JUMPHERE(lastchar); @@ -2229,91 +3186,108 @@ set_jumps(newline, loop); if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF) { - leave = JUMP(SLJIT_JUMP); + quit = JUMP(SLJIT_JUMP); JUMPHERE(foundcr); notfoundnl = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL); - COND_VALUE(SLJIT_MOV, TMP1, 0, SLJIT_C_EQUAL); -#ifdef COMPILE_PCRE16 - OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); JUMPHERE(notfoundnl); - JUMPHERE(leave); + JUMPHERE(quit); } JUMPHERE(lastchar); JUMPHERE(firstchar); if (firstline) - OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0); + OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); } +static BOOL check_class_ranges(compiler_common *common, const pcre_uint8 *bits, BOOL nclass, jump_list **backtracks); + static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common, sljit_uw start_bits, BOOL firstline) { DEFINE_COMPILER; struct sljit_label *start; -struct sljit_jump *leave; -struct sljit_jump *found; +struct sljit_jump *quit; +struct sljit_jump *found = NULL; +jump_list *matches = NULL; +pcre_uint8 inverted_start_bits[32]; +int i; #ifndef COMPILE_PCRE8 struct sljit_jump *jump; #endif +for (i = 0; i < 32; ++i) + inverted_start_bits[i] = ~(((pcre_uint8*)start_bits)[i]); + if (firstline) { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, STR_END, 0); + SLJIT_ASSERT(common->first_line_end != 0); + OP1(SLJIT_MOV, RETURN_ADDR, 0, STR_END, 0); OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end); } start = LABEL(); -leave = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); +quit = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); #ifdef SUPPORT_UTF if (common->utf) OP1(SLJIT_MOV, TMP3, 0, TMP1, 0); #endif + +if (!check_class_ranges(common, inverted_start_bits, (inverted_start_bits[31] & 0x80) != 0, &matches)) + { #ifndef COMPILE_PCRE8 -jump = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 255); -OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 255); -JUMPHERE(jump); + jump = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 255); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 255); + JUMPHERE(jump); #endif -OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); -OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); -OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), start_bits); -OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); -OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); -found = JUMP(SLJIT_C_NOT_ZERO); + OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); + OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); + OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), start_bits); + OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); + OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + found = JUMP(SLJIT_C_NOT_ZERO); + } #ifdef SUPPORT_UTF if (common->utf) OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); #endif OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#if defined SUPPORT_UTF && defined COMPILE_PCRE8 +#ifdef SUPPORT_UTF +#if defined COMPILE_PCRE8 if (common->utf) { CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0, start); - OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)PRIV(utf8_table4) - 0xc0); + OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); } -#endif -#if defined SUPPORT_UTF && defined COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 if (common->utf) { CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xd800, start); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); - COND_VALUE(SLJIT_MOV, TMP1, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); } -#endif +#endif /* COMPILE_PCRE[8|16] */ +#endif /* SUPPORT_UTF */ JUMPTO(SLJIT_JUMP, start); -JUMPHERE(found); -JUMPHERE(leave); +if (found != NULL) + JUMPHERE(found); +if (matches != NULL) + set_jumps(matches, LABEL()); +JUMPHERE(quit); if (firstline) - OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0); + OP1(SLJIT_MOV, STR_END, 0, RETURN_ADDR, 0); } static SLJIT_INLINE struct sljit_jump *search_requested_char(compiler_common *common, pcre_uchar req_char, BOOL caseless, BOOL has_firstchar) @@ -2325,7 +3299,7 @@ struct sljit_jump *alreadyfound; struct sljit_jump *found; struct sljit_jump *foundoc = NULL; struct sljit_jump *notfound; -pcre_uchar oc, bit; +pcre_uint32 oc, bit; SLJIT_ASSERT(common->req_char_ptr != 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->req_char_ptr); @@ -2356,7 +3330,7 @@ if (req_char == oc) else { bit = req_char ^ oc; - if (ispowerof2(bit)) + if (is_powerof2(bit)) { OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, bit); found = CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, req_char | bit); @@ -2392,40 +3366,25 @@ GET_LOCAL_BASE(TMP3, 0, 0); /* Drop frames until we reach STACK_TOP. */ mainloop = LABEL(); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), 0); -jump = CMP(SLJIT_C_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, frame_end); +OP2(SLJIT_SUB | SLJIT_SET_S, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0); +jump = JUMP(SLJIT_C_SIG_LESS_EQUAL); + OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP3, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(TMP1), sizeof(sljit_w)); -OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_w), SLJIT_MEM1(TMP1), 2 * sizeof(sljit_w)); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_w)); +OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(TMP1), sizeof(sljit_sw)); +OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), SLJIT_MEM1(TMP1), 2 * sizeof(sljit_sw)); +OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_sw)); JUMPTO(SLJIT_JUMP, mainloop); JUMPHERE(jump); -jump = CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, frame_end); +jump = JUMP(SLJIT_C_SIG_LESS); /* End of dropping frames. */ sljit_emit_fast_return(compiler, RETURN_ADDR, 0); JUMPHERE(jump); -jump = CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, frame_setstrbegin); -/* Set string begin. */ -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), sizeof(sljit_w)); -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_w)); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), TMP2, 0); -JUMPTO(SLJIT_JUMP, mainloop); - -JUMPHERE(jump); -if (common->mark_ptr != 0) - { - jump = CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, frame_setmark); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), sizeof(sljit_w)); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_w)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr, TMP2, 0); - JUMPTO(SLJIT_JUMP, mainloop); - - JUMPHERE(jump); - } - -/* Unknown command. */ -OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_w)); +OP1(SLJIT_NEG, TMP2, 0, TMP2, 0); +OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP3, 0); +OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(TMP1), sizeof(sljit_sw)); +OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_sw)); JUMPTO(SLJIT_JUMP, mainloop); } @@ -2433,6 +3392,7 @@ static void check_wordboundary(compiler_common *common) { DEFINE_COMPILER; struct sljit_jump *skipread; +jump_list *skipread_list = NULL; #if !(defined COMPILE_PCRE8) || defined SUPPORT_UTF struct sljit_jump *jump; #endif @@ -2458,10 +3418,10 @@ if (common->use_ucp) add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_LESS_EQUAL); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_LESS_EQUAL); JUMPHERE(jump); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, TMP2, 0); } @@ -2490,7 +3450,7 @@ else JUMPHERE(skipread); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); -skipread = check_str_end(common); +check_str_end(common, &skipread_list); peek_char(common); /* Testing char type. This is a code duplication. */ @@ -2502,10 +3462,10 @@ if (common->use_ucp) add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_LESS_EQUAL); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_LESS_EQUAL); JUMPHERE(jump); } else @@ -2531,12 +3491,151 @@ else JUMPHERE(jump); #endif /* COMPILE_PCRE8 */ } -JUMPHERE(skipread); +set_jumps(skipread_list, LABEL()); 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); } +/* + range format: + + ranges[0] = length of the range (max MAX_RANGE_SIZE, -1 means invalid range). + ranges[1] = first bit (0 or 1) + ranges[2-length] = position of the bit change (when the current bit is not equal to the previous) +*/ + +static BOOL check_ranges(compiler_common *common, int *ranges, jump_list **backtracks, BOOL readch) +{ +DEFINE_COMPILER; +struct sljit_jump *jump; + +if (ranges[0] < 0) + return FALSE; + +switch(ranges[0]) + { + case 1: + if (readch) + read_char(common); + add_jump(compiler, backtracks, CMP(ranges[1] == 0 ? SLJIT_C_LESS : SLJIT_C_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2])); + return TRUE; + + case 2: + if (readch) + read_char(common); + OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2]); + add_jump(compiler, backtracks, CMP(ranges[1] != 0 ? SLJIT_C_LESS : SLJIT_C_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[2])); + return TRUE; + + case 4: + if (ranges[2] + 1 == ranges[3] && ranges[4] + 1 == ranges[5]) + { + if (readch) + read_char(common); + if (ranges[1] != 0) + { + add_jump(compiler, backtracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2])); + add_jump(compiler, backtracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, ranges[4])); + } + else + { + jump = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2]); + add_jump(compiler, backtracks, CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[4])); + JUMPHERE(jump); + } + return TRUE; + } + if ((ranges[3] - ranges[2]) == (ranges[5] - ranges[4]) && is_powerof2(ranges[4] - ranges[2])) + { + if (readch) + read_char(common); + OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[4] - ranges[2]); + OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[4]); + add_jump(compiler, backtracks, CMP(ranges[1] != 0 ? SLJIT_C_LESS : SLJIT_C_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[5] - ranges[4])); + return TRUE; + } + return FALSE; + + default: + return FALSE; + } +} + +static void get_ctype_ranges(compiler_common *common, int flag, int *ranges) +{ +int i, bit, length; +const pcre_uint8 *ctypes = (const pcre_uint8*)common->ctypes; + +bit = ctypes[0] & flag; +ranges[0] = -1; +ranges[1] = bit != 0 ? 1 : 0; +length = 0; + +for (i = 1; i < 256; i++) + if ((ctypes[i] & flag) != bit) + { + if (length >= MAX_RANGE_SIZE) + return; + ranges[2 + length] = i; + length++; + bit ^= flag; + } + +if (bit != 0) + { + if (length >= MAX_RANGE_SIZE) + return; + ranges[2 + length] = 256; + length++; + } +ranges[0] = length; +} + +static BOOL check_class_ranges(compiler_common *common, const pcre_uint8 *bits, BOOL nclass, jump_list **backtracks) +{ +int ranges[2 + MAX_RANGE_SIZE]; +pcre_uint8 bit, cbit, all; +int i, byte, length = 0; + +bit = bits[0] & 0x1; +ranges[1] = bit; +/* Can be 0 or 255. */ +all = -bit; + +for (i = 0; i < 256; ) + { + byte = i >> 3; + if ((i & 0x7) == 0 && bits[byte] == all) + i += 8; + else + { + cbit = (bits[byte] >> (i & 0x7)) & 0x1; + if (cbit != bit) + { + if (length >= MAX_RANGE_SIZE) + return FALSE; + ranges[2 + length] = i; + length++; + bit = cbit; + all = -cbit; + } + i++; + } + } + +if (((bit == 0) && nclass) || ((bit == 1) && !nclass)) + { + if (length >= MAX_RANGE_SIZE) + return FALSE; + ranges[2 + length] = 256; + length++; + } +ranges[0] = length; + +return check_ranges(common, ranges, backtracks, FALSE); +} + static void check_anynewline(compiler_common *common) { /* Check whether TMP1 contains a newline character. TMP2 destroyed. */ @@ -2546,21 +3645,21 @@ sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); -COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL); +OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_LESS_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); -#if defined SUPPORT_UTF || defined COMPILE_PCRE16 +#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 #ifdef COMPILE_PCRE8 if (common->utf) { #endif - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); #ifdef COMPILE_PCRE8 } #endif -#endif /* SUPPORT_UTF || COMPILE_PCRE16 */ -COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); +#endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */ +OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } @@ -2572,33 +3671,33 @@ DEFINE_COMPILER; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x09); -COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL); +OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20); -COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL); +OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0); -#if defined SUPPORT_UTF || defined COMPILE_PCRE16 +#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 #ifdef COMPILE_PCRE8 if (common->utf) { #endif - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x1680); - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e); - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2000); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000); - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_LESS_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000); - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000); - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000); #ifdef COMPILE_PCRE8 } #endif -#endif /* SUPPORT_UTF || COMPILE_PCRE16 */ -COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); +#endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */ +OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } @@ -2612,21 +3711,21 @@ sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); -COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL); +OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_LESS_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); -#if defined SUPPORT_UTF || defined COMPILE_PCRE16 +#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 #ifdef COMPILE_PCRE8 if (common->utf) { #endif - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); #ifdef COMPILE_PCRE8 } #endif -#endif /* SUPPORT_UTF || COMPILE_PCRE16 */ -COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); +#endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */ +OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } @@ -2712,12 +3811,14 @@ sljit_emit_fast_return(compiler, RETURN_ADDR, 0); #if defined SUPPORT_UTF && defined SUPPORT_UCP -static const pcre_uchar *SLJIT_CALL do_utf_caselesscmp(pcre_uchar *src1, jit_arguments *args, pcre_uchar *end1) +static const pcre_uchar * SLJIT_CALL do_utf_caselesscmp(pcre_uchar *src1, jit_arguments *args, pcre_uchar *end1) { /* This function would be ineffective to do in JIT level. */ -int c1, c2; +pcre_uint32 c1, c2; const pcre_uchar *src2 = args->uchar_ptr; const pcre_uchar *end2 = args->end; +const ucd_record *ur; +const pcre_uint32 *pp; while (src1 < end1) { @@ -2725,7 +3826,16 @@ while (src1 < end1) return (pcre_uchar*)1; GETCHARINC(c1, src1); GETCHARINC(c2, src2); - if (c1 != c2 && c1 != UCD_OTHERCASE(c2)) return NULL; + ur = GET_UCD(c2); + if (c1 != c2 && c1 != c2 + ur->other_case) + { + pp = PRIV(ucd_caseless_sets) + ur->caseset; + for (;;) + { + if (c1 < *pp) return NULL; + if (c1 == *pp++) break; + } + } } return src2; } @@ -2747,23 +3857,25 @@ if (caseless && char_has_othercase(common, cc)) othercasebit = char_get_othercase_bit(common, cc); SLJIT_ASSERT(othercasebit); /* Extracting bit difference info. */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 othercasechar = cc + (othercasebit >> 8); othercasebit &= 0xff; -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + /* Note that this code only handles characters in the BMP. If there + ever are characters outside the BMP whose othercase differs in only one + bit from itself (there currently are none), this code will need to be + revised for COMPILE_PCRE32. */ othercasechar = cc + (othercasebit >> 9); if ((othercasebit & 0x100) != 0) othercasebit = (othercasebit & 0xff) << 8; else othercasebit &= 0xff; -#endif -#endif +#endif /* COMPILE_PCRE[8|16|32] */ } if (context->sourcereg == -1) { -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED if (context->length >= 4) OP1(SLJIT_MOV_SI, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); @@ -2772,16 +3884,16 @@ if (context->sourcereg == -1) else #endif OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); -#else -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED if (context->length >= 4) OP1(SLJIT_MOV_SI, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); else #endif - OP1(SLJIT_MOV_UH, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); -#endif -#endif /* COMPILE_PCRE8 */ + OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); +#elif defined COMPILE_PCRE32 + OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); +#endif /* COMPILE_PCRE[8|16|32] */ context->sourcereg = TMP2; } @@ -2795,7 +3907,7 @@ do #endif context->length -= IN_UCHARS(1); -#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED +#if (defined SLJIT_UNALIGNED && SLJIT_UNALIGNED) && (defined COMPILE_PCRE8 || defined COMPILE_PCRE16) /* Unaligned read is supported. */ if (othercasebit != 0 && othercasechar == cc) @@ -2810,7 +3922,7 @@ do } context->ucharptr++; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 if (context->ucharptr >= 4 || context->length == 0 || (context->ucharptr == 2 && context->length == 1)) #else if (context->ucharptr >= 2 || context->length == 0) @@ -2818,15 +3930,12 @@ do { if (context->length >= 4) OP1(SLJIT_MOV_SI, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); -#ifdef COMPILE_PCRE8 else if (context->length >= 2) OP1(SLJIT_MOV_UH, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); +#if defined COMPILE_PCRE8 else if (context->length >= 1) OP1(SLJIT_MOV_UB, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); -#else - else if (context->length >= 2) - OP1(SLJIT_MOV_UH, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); -#endif +#endif /* COMPILE_PCRE8 */ context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1; switch(context->ucharptr) @@ -2860,14 +3969,10 @@ do #else - /* Unaligned read is unsupported. */ -#ifdef COMPILE_PCRE8 - if (context->length > 0) - OP1(SLJIT_MOV_UB, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); -#else - if (context->length > 0) - OP1(SLJIT_MOV_UH, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); -#endif + /* Unaligned read is unsupported or in 32 bit mode. */ + if (context->length >= 1) + OP1(MOV_UCHAR, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); + context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1; if (othercasebit != 0 && othercasechar == cc) @@ -2912,25 +4017,26 @@ return cc; } \ charoffset = (value); -static void compile_xclass_trypath(compiler_common *common, pcre_uchar *cc, jump_list **backtracks) +static void compile_xclass_matchingpath(compiler_common *common, pcre_uchar *cc, jump_list **backtracks) { DEFINE_COMPILER; jump_list *found = NULL; jump_list **list = (*cc & XCL_NOT) == 0 ? &found : backtracks; -unsigned int c; -int compares; +pcre_int32 c, charoffset; struct sljit_jump *jump = NULL; pcre_uchar *ccbegin; +int compares, invertcmp, numberofcmps; + #ifdef SUPPORT_UCP BOOL needstype = FALSE, needsscript = FALSE, needschar = FALSE; BOOL charsaved = FALSE; int typereg = TMP1, scriptreg = TMP1; -unsigned int typeoffset; +const pcre_uint32 *other_cases; +pcre_int32 typeoffset; #endif -int invertcmp, numberofcmps; -unsigned int charoffset; -/* Although SUPPORT_UTF must be defined, we are not necessary in utf mode. */ +/* Although SUPPORT_UTF must be defined, we are + not necessary in utf mode even in 8 bit mode. */ detect_partial_match(common, backtracks); read_char(common); @@ -2944,12 +4050,15 @@ if ((*cc++ & XCL_MAP) != 0) jump = CMP(SLJIT_C_GREATER, TMP1, 0, SLJIT_IMM, 255); #endif - OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); - OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); - OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)cc); - OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); - add_jump(compiler, list, JUMP(SLJIT_C_NOT_ZERO)); + if (!check_class_ranges(common, (const pcre_uint8 *)cc, TRUE, list)) + { + OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); + OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); + OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); + OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); + OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + add_jump(compiler, list, JUMP(SLJIT_C_NOT_ZERO)); + } #ifndef COMPILE_PCRE8 JUMPHERE(jump); @@ -3018,10 +4127,18 @@ while (*cc != XCL_END) case PT_SPACE: case PT_PXSPACE: case PT_WORD: + case PT_PXGRAPH: + case PT_PXPRINT: + case PT_PXPUNCT: needstype = TRUE; needschar = TRUE; break; + case PT_CLIST: + case PT_UCNC: + needschar = TRUE; + break; + default: SLJIT_ASSERT_STOP(); break; @@ -3058,13 +4175,13 @@ if (needstype || needsscript) { if (scriptreg == TMP1) { - OP1(SLJIT_MOV, scriptreg, 0, SLJIT_IMM, (sljit_w)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script)); + OP1(SLJIT_MOV, scriptreg, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script)); OP1(SLJIT_MOV_UB, scriptreg, 0, SLJIT_MEM2(scriptreg, TMP2), 3); } else { OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 3); - OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, (sljit_w)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script)); + OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script)); OP1(SLJIT_MOV_UB, scriptreg, 0, SLJIT_MEM1(TMP2), 0); } } @@ -3100,13 +4217,13 @@ while (*cc != XCL_END) if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE)) { OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c - charoffset); - COND_VALUE(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, numberofcmps == 0 ? SLJIT_UNUSED : TMP2, 0, SLJIT_C_EQUAL); numberofcmps++; } else if (numberofcmps > 0) { OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c - charoffset); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp); numberofcmps = 0; } @@ -3139,13 +4256,13 @@ while (*cc != XCL_END) if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE)) { OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c - charoffset); - COND_VALUE(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, numberofcmps == 0 ? SLJIT_UNUSED : TMP2, 0, SLJIT_C_LESS_EQUAL); numberofcmps++; } else if (numberofcmps > 0) { OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, c - charoffset); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_LESS_EQUAL); jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp); numberofcmps = 0; } @@ -3176,11 +4293,11 @@ while (*cc != XCL_END) case PT_LAMP: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset); - COND_VALUE(SLJIT_OR, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp); break; @@ -3200,35 +4317,165 @@ while (*cc != XCL_END) case PT_SPACE: case PT_PXSPACE: - if (*cc == PT_SPACE) - { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); - jump = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, 11 - charoffset); - } SET_CHAR_OFFSET(9); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 13 - 9); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS_EQUAL); - if (*cc == PT_SPACE) - JUMPHERE(jump); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd - 0x9); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_LESS_EQUAL); + + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x9); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); + + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x9); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); SET_TYPE_OFFSET(ucp_Zl); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_LESS_EQUAL); jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp); break; case PT_WORD: OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE - charoffset); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_EQUAL); - /* ... fall through */ + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); + /* Fall through. */ case PT_ALNUM: SET_TYPE_OFFSET(ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); - COND_VALUE((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, (*cc == PT_ALNUM) ? SLJIT_UNUSED : TMP2, 0, SLJIT_C_LESS_EQUAL); SET_TYPE_OFFSET(ucp_Nd); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_LESS_EQUAL); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_LESS_EQUAL); + jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp); + break; + + case PT_CLIST: + other_cases = PRIV(ucd_caseless_sets) + cc[1]; + + /* At least three characters are required. + Otherwise this case would be handled by the normal code path. */ + SLJIT_ASSERT(other_cases[0] != NOTACHAR && other_cases[1] != NOTACHAR && other_cases[2] != NOTACHAR); + SLJIT_ASSERT(other_cases[0] < other_cases[1] && other_cases[1] < other_cases[2]); + + /* Optimizing character pairs, if their difference is power of 2. */ + if (is_powerof2(other_cases[1] ^ other_cases[0])) + { + if (charoffset == 0) + OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); + else + { + OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset); + OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); + } + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[1]); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); + other_cases += 2; + } + else if (is_powerof2(other_cases[2] ^ other_cases[1])) + { + if (charoffset == 0) + OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[2] ^ other_cases[1]); + else + { + OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset); + OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); + } + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[2]); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); + + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, other_cases[0] - charoffset); + OP_FLAGS(SLJIT_OR | ((other_cases[3] == NOTACHAR) ? SLJIT_SET_E : 0), TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); + + other_cases += 3; + } + else + { + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, *other_cases++ - charoffset); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); + } + + while (*other_cases != NOTACHAR) + { + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, *other_cases++ - charoffset); + OP_FLAGS(SLJIT_OR | ((*other_cases == NOTACHAR) ? SLJIT_SET_E : 0), TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); + } + jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp); + break; + + case PT_UCNC: + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_DOLLAR_SIGN - charoffset); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_COMMERCIAL_AT - charoffset); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_GRAVE_ACCENT - charoffset); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); + + SET_CHAR_OFFSET(0xa0); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd7ff - charoffset); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_LESS_EQUAL); + SET_CHAR_OFFSET(0); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xe000 - 0); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_GREATER_EQUAL); + jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp); + break; + + case PT_PXGRAPH: + /* C and Z groups are the farthest two groups. */ + SET_TYPE_OFFSET(ucp_Ll); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_GREATER); + + jump = CMP(SLJIT_C_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll); + + /* In case of ucp_Cf, we overwrite the result. */ + SET_CHAR_OFFSET(0x2066); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_LESS_EQUAL); + + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); + + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); + + JUMPHERE(jump); + jump = CMP(SLJIT_C_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0); + break; + + case PT_PXPRINT: + /* C and Z groups are the farthest two groups. */ + SET_TYPE_OFFSET(ucp_Ll); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_GREATER); + + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll); + OP_FLAGS(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_C_NOT_EQUAL); + + jump = CMP(SLJIT_C_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll); + + /* In case of ucp_Cf, we overwrite the result. */ + SET_CHAR_OFFSET(0x2066); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_LESS_EQUAL); + + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); + OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); + + JUMPHERE(jump); + jump = CMP(SLJIT_C_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0); + break; + + case PT_PXPUNCT: + SET_TYPE_OFFSET(ucp_Sc); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_LESS_EQUAL); + + SET_CHAR_OFFSET(0); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xff); + OP_FLAGS(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_C_LESS_EQUAL); + + SET_TYPE_OFFSET(ucp_Pc); + OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_LESS_EQUAL); jump = JUMP(SLJIT_C_NOT_ZERO ^ invertcmp); break; } @@ -3249,13 +4496,14 @@ if (found != NULL) #endif -static pcre_uchar *compile_char1_trypath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks) +static pcre_uchar *compile_char1_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks) { DEFINE_COMPILER; int length; unsigned int c, oc, bit; compare_context context; struct sljit_jump *jump[4]; +jump_list *end_list; #ifdef SUPPORT_UTF struct sljit_label *label; #ifdef SUPPORT_UCP @@ -3285,10 +4533,21 @@ switch(type) case OP_NOT_DIGIT: case OP_DIGIT: + /* Digits are usually 0-9, so it is worth to optimize them. */ + if (common->digits[0] == -2) + get_ctype_ranges(common, ctype_digit, common->digits); detect_partial_match(common, backtracks); - read_char8_type(common); - OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit); - add_jump(compiler, backtracks, JUMP(type == OP_DIGIT ? SLJIT_C_ZERO : SLJIT_C_NOT_ZERO)); + /* Flip the starting bit in the negative case. */ + if (type == OP_NOT_DIGIT) + common->digits[1] ^= 1; + if (!check_ranges(common, common->digits, backtracks, TRUE)) + { + read_char8_type(common); + OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit); + add_jump(compiler, backtracks, JUMP(type == OP_DIGIT ? SLJIT_C_ZERO : SLJIT_C_NOT_ZERO)); + } + if (type == OP_NOT_DIGIT) + common->digits[1] ^= 1; return cc; case OP_NOT_WHITESPACE: @@ -3313,15 +4572,15 @@ switch(type) if (common->nltype == NLTYPE_FIXED && common->newline > 255) { jump[0] = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff); + end_list = NULL; if (common->mode != JIT_PARTIAL_HARD_COMPILE) - jump[1] = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); + add_jump(compiler, &end_list, CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); else - jump[1] = check_str_end(common); + check_str_end(common, &end_list); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); add_jump(compiler, backtracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, common->newline & 0xff)); - if (jump[1] != NULL) - JUMPHERE(jump[1]); + set_jumps(end_list, LABEL()); JUMPHERE(jump[0]); } else @@ -3335,21 +4594,21 @@ switch(type) { OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 +#if defined COMPILE_PCRE8 jump[0] = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0); - OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)PRIV(utf8_table4) - 0xc0); + OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -#else /* COMPILE_PCRE8 */ -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 jump[0] = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xd800); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); - COND_VALUE(SLJIT_MOV, TMP1, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); -#endif /* COMPILE_PCRE16 */ -#endif /* COMPILE_PCRE8 */ +#endif JUMPHERE(jump[0]); +#endif /* COMPILE_PCRE[8|16] */ return cc; } #endif @@ -3370,7 +4629,7 @@ switch(type) propdata[2] = cc[0]; propdata[3] = cc[1]; propdata[4] = XCL_END; - compile_xclass_trypath(common, propdata, backtracks); + compile_xclass_matchingpath(common, propdata, backtracks); return cc + 2; #endif #endif @@ -3380,19 +4639,20 @@ switch(type) read_char(common); jump[0] = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); /* We don't need to handle soft partial matching case. */ + end_list = NULL; if (common->mode != JIT_PARTIAL_HARD_COMPILE) - jump[1] = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); + add_jump(compiler, &end_list, CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); else - jump[1] = check_str_end(common); + check_str_end(common, &end_list); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); - jump[2] = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL); + jump[1] = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); - jump[3] = JUMP(SLJIT_JUMP); + jump[2] = JUMP(SLJIT_JUMP); JUMPHERE(jump[0]); check_newlinechar(common, common->bsr_nltype, backtracks, FALSE); + set_jumps(end_list, LABEL()); JUMPHERE(jump[1]); JUMPHERE(jump[2]); - JUMPHERE(jump[3]); return cc; case OP_NOT_HSPACE: @@ -3416,19 +4676,30 @@ switch(type) detect_partial_match(common, backtracks); read_char(common); add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Mc); - add_jump(compiler, backtracks, CMP(SLJIT_C_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_Mn - ucp_Mc)); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop)); + /* Optimize register allocation: use a real register. */ + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, STACK_TOP, 0); + OP1(SLJIT_MOV_UB, STACK_TOP, 0, SLJIT_MEM2(TMP1, TMP2), 3); label = LABEL(); jump[0] = CMP(SLJIT_C_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); read_char(common); add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Mc); - CMPTO(SLJIT_C_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_Mn - ucp_Mc, label); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop)); + OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM2(TMP1, TMP2), 3); + + OP2(SLJIT_SHL, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2); + OP1(SLJIT_MOV_UI, TMP1, 0, SLJIT_MEM1(STACK_TOP), (sljit_sw)PRIV(ucp_gbtable)); + OP1(SLJIT_MOV, STACK_TOP, 0, TMP2, 0); + OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); + OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + JUMPTO(SLJIT_C_NOT_ZERO, label); OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); JUMPHERE(jump[0]); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0); + if (common->mode == JIT_PARTIAL_HARD_COMPILE) { jump[0] = CMP(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0); @@ -3452,9 +4723,9 @@ switch(type) { jump[1] = CMP(SLJIT_C_EQUAL, TMP2, 0, STR_END, 0); OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_LESS); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_LESS); OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_NOT_EQUAL); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_NOT_EQUAL); add_jump(compiler, backtracks, JUMP(SLJIT_C_NOT_EQUAL)); check_partial(common, TRUE); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); @@ -3554,7 +4825,7 @@ switch(type) add_jump(compiler, backtracks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); if (!common->endonly) - compile_char1_trypath(common, OP_EODN, cc, backtracks); + compile_char1_matchingpath(common, OP_EODN, cc, backtracks); else { add_jump(compiler, backtracks, CMP(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0)); @@ -3634,16 +4905,16 @@ switch(type) } oc = char_othercase(common, c); bit = c ^ oc; - if (ispowerof2(bit)) + if (is_powerof2(bit)) { OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit); add_jump(compiler, backtracks, 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)); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_C_EQUAL); + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, oc); + OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_C_EQUAL); add_jump(compiler, backtracks, JUMP(SLJIT_C_ZERO)); return cc + length; @@ -3670,7 +4941,7 @@ switch(type) /* Skip the variable-length character. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); jump[0] = CMP(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, 0xc0); - OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)PRIV(utf8_table4) - 0xc0); + OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); JUMPHERE(jump[0]); return cc + 1; @@ -3695,7 +4966,7 @@ switch(type) { oc = char_othercase(common, c); bit = c ^ oc; - if (ispowerof2(bit)) + if (is_powerof2(bit)) { OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit); add_jump(compiler, backtracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_IMM, c | bit)); @@ -3712,6 +4983,9 @@ switch(type) case OP_NCLASS: detect_partial_match(common, backtracks); read_char(common); + if (check_class_ranges(common, (const pcre_uint8 *)cc, type == OP_NCLASS, backtracks)) + return cc + 32 / sizeof(pcre_uchar); + #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 jump[0] = NULL; #ifdef COMPILE_PCRE8 @@ -3730,7 +5004,7 @@ switch(type) #endif /* SUPPORT_UTF || !COMPILE_PCRE8 */ OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); - OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_w)cc); + OP1(SLJIT_MOV_UB, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); add_jump(compiler, backtracks, JUMP(SLJIT_C_ZERO)); @@ -3740,9 +5014,9 @@ switch(type) #endif /* SUPPORT_UTF || !COMPILE_PCRE8 */ return cc + 32 / sizeof(pcre_uchar); -#if defined SUPPORT_UTF || defined COMPILE_PCRE16 +#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case OP_XCLASS: - compile_xclass_trypath(common, cc + LINK_SIZE, backtracks); + compile_xclass_matchingpath(common, cc + LINK_SIZE, backtracks); return cc + GET(cc, 0) - 1; #endif @@ -3776,7 +5050,7 @@ SLJIT_ASSERT_STOP(); return cc; } -static SLJIT_INLINE pcre_uchar *compile_charn_trypath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, jump_list **backtracks) +static SLJIT_INLINE pcre_uchar *compile_charn_matchingpath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, jump_list **backtracks) { /* This function consumes at least one input character. */ /* To decrease the number of length checks, we try to concatenate the fixed length character sequences. */ @@ -3839,34 +5113,12 @@ if (context.length > 0) } /* A non-fixed length character will be checked if length == 0. */ -return compile_char1_trypath(common, *cc, cc + 1, backtracks); -} - -static struct sljit_jump *compile_ref_checks(compiler_common *common, pcre_uchar *cc, jump_list **backtracks) -{ -DEFINE_COMPILER; -int offset = GET2(cc, 1) << 1; - -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset)); -if (!common->jscript_compat) - { - if (backtracks == 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)); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_EQUAL); - return JUMP(SLJIT_C_NOT_ZERO); - } - add_jump(compiler, backtracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1))); - } -return CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); +return compile_char1_matchingpath(common, *cc, cc + 1, backtracks); } /* Forward definitions. */ -static void compile_trypath(compiler_common *, pcre_uchar *, pcre_uchar *, backtrack_common *); -static void compile_backtrackpath(compiler_common *, struct backtrack_common *); +static void compile_matchingpath(compiler_common *, pcre_uchar *, pcre_uchar *, backtrack_common *); +static void compile_backtrackingpath(compiler_common *, struct backtrack_common *); #define PUSH_BACKTRACK(size, ccstart, error) \ do \ @@ -3896,31 +5148,72 @@ static void compile_backtrackpath(compiler_common *, struct backtrack_common *); #define BACKTRACK_AS(type) ((type *)backtrack) -static pcre_uchar *compile_ref_trypath(compiler_common *common, pcre_uchar *cc, jump_list **backtracks, BOOL withchecks, BOOL emptyfail) +static void compile_dnref_search(compiler_common *common, pcre_uchar *cc, jump_list **backtracks) +{ +/* The OVECTOR offset goes to TMP2. */ +DEFINE_COMPILER; +int count = GET2(cc, 1 + IMM2_SIZE); +pcre_uchar *slot = common->name_table + GET2(cc, 1) * common->name_entry_size; +unsigned int offset; +jump_list *found = NULL; + +SLJIT_ASSERT(*cc == OP_DNREF || *cc == OP_DNREFI); + +OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1)); + +count--; +while (count-- > 0) + { + offset = GET2(slot, 0) << 1; + GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset)); + add_jump(compiler, &found, CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0)); + slot += common->name_entry_size; + } + +offset = GET2(slot, 0) << 1; +GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset)); +if (backtracks != NULL && !common->jscript_compat) + add_jump(compiler, backtracks, CMP(SLJIT_C_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0)); + +set_jumps(found, LABEL()); +} + +static void compile_ref_matchingpath(compiler_common *common, pcre_uchar *cc, jump_list **backtracks, BOOL withchecks, BOOL emptyfail) { DEFINE_COMPILER; -int offset = GET2(cc, 1) << 1; +BOOL ref = (*cc == OP_REF || *cc == OP_REFI); +int offset = 0; struct sljit_jump *jump = NULL; struct sljit_jump *partial; struct sljit_jump *nopartial; -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, backtracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1))); +if (ref) + { + offset = GET2(cc, 1) << 1; + 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, backtracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1))); + } +else + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); #if defined SUPPORT_UTF && defined SUPPORT_UCP if (common->utf && *cc == OP_REFI) { - SLJIT_ASSERT(TMP1 == SLJIT_TEMPORARY_REG1 && STACK_TOP == SLJIT_TEMPORARY_REG2 && TMP2 == SLJIT_TEMPORARY_REG3); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); + SLJIT_ASSERT(TMP1 == SLJIT_SCRATCH_REG1 && STACK_TOP == SLJIT_SCRATCH_REG2 && TMP2 == SLJIT_SCRATCH_REG3); + if (ref) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); + else + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); + if (withchecks) jump = CMP(SLJIT_C_EQUAL, TMP1, 0, TMP2, 0); /* 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); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_TEMPORARY_REG2), SLJIT_OFFSETOF(jit_arguments, uchar_ptr), STR_PTR, 0); + OP1(SLJIT_MOV, SLJIT_SCRATCH_REG2, 0, ARGUMENTS, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SCRATCH_REG2), SLJIT_OFFSETOF(jit_arguments, uchar_ptr), STR_PTR, 0); sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_utf_caselesscmp)); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0); if (common->mode == JIT_COMPILE) @@ -3938,7 +5231,11 @@ if (common->utf && *cc == OP_REFI) else #endif /* SUPPORT_UTF && SUPPORT_UCP */ { - OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP1, 0); + if (ref) + OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP1, 0); + else + OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0); + if (withchecks) jump = JUMP(SLJIT_C_ZERO); @@ -3975,14 +5272,15 @@ if (jump != NULL) else JUMPHERE(jump); } -return cc + 1 + IMM2_SIZE; } -static SLJIT_INLINE pcre_uchar *compile_ref_iterator_trypath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) +static SLJIT_INLINE pcre_uchar *compile_ref_iterator_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; +BOOL ref = (*cc == OP_REF || *cc == OP_REFI); backtrack_common *backtrack; pcre_uchar type; +int offset = 0; struct sljit_label *label; struct sljit_jump *zerolength; struct sljit_jump *jump = NULL; @@ -3992,7 +5290,13 @@ BOOL minimize; PUSH_BACKTRACK(sizeof(iterator_backtrack), cc, NULL); +if (ref) + offset = GET2(cc, 1) << 1; +else + cc += IMM2_SIZE; type = cc[1 + IMM2_SIZE]; + +SLJIT_COMPILE_ASSERT((OP_CRSTAR & 0x1) == 0, crstar_opcode_must_be_even); minimize = (type & 0x1) != 0; switch(type) { @@ -4030,26 +5334,53 @@ if (!minimize) if (min == 0) { allocate_stack(common, 2); + if (ref) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0); /* Temporary release of STR_PTR. */ - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w)); - zerolength = compile_ref_checks(common, ccbegin, NULL); + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); + /* Handles both invalid and empty cases. Since the minimum repeat, + is zero the invalid case is basically the same as an empty case. */ + if (ref) + zerolength = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); + else + { + compile_dnref_search(common, ccbegin, NULL); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, TMP2, 0); + zerolength = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); + } /* Restore if not zero length. */ - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); } else { allocate_stack(common, 1); + if (ref) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - zerolength = compile_ref_checks(common, ccbegin, &backtrack->topbacktracks); + if (ref) + { + add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1))); + zerolength = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); + } + else + { + compile_dnref_search(common, ccbegin, &backtrack->topbacktracks); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, TMP2, 0); + zerolength = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); + } } if (min > 1 || max > 1) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 0); label = LABEL(); - compile_ref_trypath(common, ccbegin, &backtrack->topbacktracks, FALSE, FALSE); + if (!ref) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1); + compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, FALSE, FALSE); if (min > 1 || max > 1) { @@ -4077,31 +5408,59 @@ if (!minimize) } JUMPHERE(zerolength); - BACKTRACK_AS(iterator_backtrack)->trypath = LABEL(); + BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL(); - decrease_call_count(common); + count_match(common); return cc; } -allocate_stack(common, 2); +allocate_stack(common, ref ? 2 : 3); +if (ref) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); if (type != OP_CRMINSTAR) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0); if (min == 0) { - zerolength = compile_ref_checks(common, ccbegin, NULL); + /* Handles both invalid and empty cases. Since the minimum repeat, + is zero the invalid case is basically the same as an empty case. */ + if (ref) + zerolength = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); + else + { + compile_dnref_search(common, ccbegin, NULL); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0); + zerolength = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); + } + /* Length is non-zero, we can match real repeats. */ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); jump = JUMP(SLJIT_JUMP); } else - zerolength = compile_ref_checks(common, ccbegin, &backtrack->topbacktracks); + { + if (ref) + { + add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1))); + zerolength = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); + } + else + { + compile_dnref_search(common, ccbegin, &backtrack->topbacktracks); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0); + zerolength = CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); + } + } -BACKTRACK_AS(iterator_backtrack)->trypath = LABEL(); +BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL(); if (max > 0) add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_GREATER_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, max)); -compile_ref_trypath(common, ccbegin, &backtrack->topbacktracks, TRUE, TRUE); +if (!ref) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(2)); +compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, TRUE, TRUE); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); if (min > 1) @@ -4109,7 +5468,7 @@ if (min > 1) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, min, BACKTRACK_AS(iterator_backtrack)->trypath); + CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, min, BACKTRACK_AS(iterator_backtrack)->matchingpath); } else if (max > 0) OP2(SLJIT_ADD, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1); @@ -4118,19 +5477,31 @@ if (jump != NULL) JUMPHERE(jump); JUMPHERE(zerolength); -decrease_call_count(common); +count_match(common); return cc; } -static SLJIT_INLINE pcre_uchar *compile_recurse_trypath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) +static SLJIT_INLINE pcre_uchar *compile_recurse_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; recurse_entry *entry = common->entries; recurse_entry *prev = NULL; -int start = GET(cc, 1); +sljit_sw start = GET(cc, 1); +pcre_uchar *start_cc; +BOOL needs_control_head; PUSH_BACKTRACK(sizeof(recurse_backtrack), cc, NULL); + +/* Inlining simple patterns. */ +if (get_framesize(common, common->start + start, NULL, TRUE, &needs_control_head) == no_stack) + { + start_cc = common->start + start; + compile_matchingpath(common, next_opcode(common, start_cc), bracketend(start_cc) - (1 + LINK_SIZE), backtrack); + BACKTRACK_AS(recurse_backtrack)->inlined_pattern = TRUE; + return cc + 1 + LINK_SIZE; + } + while (entry != NULL) { if (entry->start == start) @@ -4179,11 +5550,112 @@ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_EQUAL, TMP1, 0, SLJIT_ return cc + 1 + LINK_SIZE; } -static pcre_uchar *compile_assert_trypath(compiler_common *common, pcre_uchar *cc, assert_backtrack *backtrack, BOOL conditional) +static int SLJIT_CALL do_callout(struct jit_arguments* arguments, PUBL(callout_block) *callout_block, pcre_uchar **jit_ovector) +{ +const pcre_uchar *begin = arguments->begin; +int *offset_vector = arguments->offsets; +int offset_count = arguments->offset_count; +int i; + +if (PUBL(callout) == NULL) + return 0; + +callout_block->version = 2; +callout_block->callout_data = arguments->callout_data; + +/* Offsets in subject. */ +callout_block->subject_length = arguments->end - arguments->begin; +callout_block->start_match = (pcre_uchar*)callout_block->subject - arguments->begin; +callout_block->current_position = (pcre_uchar*)callout_block->offset_vector - arguments->begin; +#if defined COMPILE_PCRE8 +callout_block->subject = (PCRE_SPTR)begin; +#elif defined COMPILE_PCRE16 +callout_block->subject = (PCRE_SPTR16)begin; +#elif defined COMPILE_PCRE32 +callout_block->subject = (PCRE_SPTR32)begin; +#endif + +/* Convert and copy the JIT offset vector to the offset_vector array. */ +callout_block->capture_top = 0; +callout_block->offset_vector = offset_vector; +for (i = 2; i < offset_count; i += 2) + { + offset_vector[i] = jit_ovector[i] - begin; + offset_vector[i + 1] = jit_ovector[i + 1] - begin; + if (jit_ovector[i] >= begin) + callout_block->capture_top = i; + } + +callout_block->capture_top = (callout_block->capture_top >> 1) + 1; +if (offset_count > 0) + offset_vector[0] = -1; +if (offset_count > 1) + offset_vector[1] = -1; +return (*PUBL(callout))(callout_block); +} + +/* Aligning to 8 byte. */ +#define CALLOUT_ARG_SIZE \ + (((int)sizeof(PUBL(callout_block)) + 7) & ~7) + +#define CALLOUT_ARG_OFFSET(arg) \ + (-CALLOUT_ARG_SIZE + SLJIT_OFFSETOF(PUBL(callout_block), arg)) + +static SLJIT_INLINE pcre_uchar *compile_callout_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) +{ +DEFINE_COMPILER; +backtrack_common *backtrack; + +PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); + +allocate_stack(common, CALLOUT_ARG_SIZE / sizeof(sljit_sw)); + +OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr); +OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); +SLJIT_ASSERT(common->capture_last_ptr != 0); +OP1(SLJIT_MOV_SI, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, cc[1]); +OP1(SLJIT_MOV_SI, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0); + +/* These pointer sized fields temporarly stores internal variables. */ +OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0)); +OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(offset_vector), STR_PTR, 0); +OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(subject), TMP2, 0); + +if (common->mark_ptr != 0) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr)); +OP1(SLJIT_MOV_SI, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(pattern_position), SLJIT_IMM, GET(cc, 2)); +OP1(SLJIT_MOV_SI, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(next_item_length), SLJIT_IMM, GET(cc, 2 + LINK_SIZE)); +OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_ptr != 0) ? TMP2 : SLJIT_IMM, 0); + +/* Needed to save important temporary registers. */ +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, STACK_TOP, 0); +OP2(SLJIT_SUB, SLJIT_SCRATCH_REG2, 0, STACK_TOP, 0, SLJIT_IMM, CALLOUT_ARG_SIZE); +GET_LOCAL_BASE(SLJIT_SCRATCH_REG3, 0, OVECTOR_START); +sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout)); +OP1(SLJIT_MOV_SI, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0); +OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0); +free_stack(common, CALLOUT_ARG_SIZE / sizeof(sljit_sw)); + +/* Check return value. */ +OP2(SLJIT_SUB | SLJIT_SET_S, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); +add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_C_SIG_GREATER)); +if (common->forced_quit_label == NULL) + add_jump(compiler, &common->forced_quit, JUMP(SLJIT_C_SIG_LESS)); +else + JUMPTO(SLJIT_C_SIG_LESS, common->forced_quit_label); +return cc + 2 + 2 * LINK_SIZE; +} + +#undef CALLOUT_ARG_SIZE +#undef CALLOUT_ARG_OFFSET + +static pcre_uchar *compile_assert_matchingpath(compiler_common *common, pcre_uchar *cc, assert_backtrack *backtrack, BOOL conditional) { DEFINE_COMPILER; int framesize; -int localptr; +int extrasize; +BOOL needs_control_head; +int private_data_ptr; backtrack_common altbacktrack; pcre_uchar *ccbegin; pcre_uchar opcode; @@ -4192,24 +5664,31 @@ jump_list *tmp = NULL; jump_list **target = (conditional) ? &backtrack->condfailed : &backtrack->common.topbacktracks; jump_list **found; /* Saving previous accept variables. */ -struct sljit_label *save_leavelabel = common->leavelabel; -struct sljit_label *save_acceptlabel = common->acceptlabel; -jump_list *save_leave = common->leave; +BOOL save_local_exit = common->local_exit; +BOOL save_positive_assert = common->positive_assert; +then_trap_backtrack *save_then_trap = common->then_trap; +struct sljit_label *save_quit_label = common->quit_label; +struct sljit_label *save_accept_label = common->accept_label; +jump_list *save_quit = common->quit; +jump_list *save_positive_assert_quit = common->positive_assert_quit; jump_list *save_accept = common->accept; struct sljit_jump *jump; struct sljit_jump *brajump = NULL; +/* Assert captures then. */ +common->then_trap = NULL; + if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) { SLJIT_ASSERT(!conditional); bra = *cc; cc++; } -localptr = PRIV_DATA(cc); -SLJIT_ASSERT(localptr != 0); -framesize = get_framesize(common, cc, FALSE); +private_data_ptr = PRIVATE_DATA(cc); +SLJIT_ASSERT(private_data_ptr != 0); +framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head); backtrack->framesize = framesize; -backtrack->localptr = localptr; +backtrack->private_data_ptr = private_data_ptr; opcode = *cc; SLJIT_ASSERT(opcode >= OP_ASSERT && opcode <= OP_ASSERTBACK_NOT); found = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) ? &tmp : target; @@ -4226,27 +5705,56 @@ if (bra == OP_BRAMINZERO) if (framesize < 0) { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0); - allocate_stack(common, 1); + extrasize = needs_control_head ? 2 : 1; + if (framesize == no_frame) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STACK_TOP, 0); + allocate_stack(common, extrasize); + if (needs_control_head) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); + if (needs_control_head) + { + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_IMM, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); + } } else { - allocate_stack(common, framesize + 2); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, -STACK(framesize + 1)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP2, 0); + extrasize = needs_control_head ? 3 : 2; + allocate_stack(common, framesize + extrasize); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, TMP2, 0); + if (needs_control_head) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - init_frame(common, ccbegin, framesize + 1, 2, FALSE); + if (needs_control_head) + { + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_IMM, 0); + } + else + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); + init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize, FALSE); } memset(&altbacktrack, 0, sizeof(backtrack_common)); -common->leavelabel = NULL; -common->leave = NULL; +if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) + { + /* Negative assert is stronger than positive assert. */ + common->local_exit = TRUE; + common->quit_label = NULL; + common->quit = NULL; + common->positive_assert = FALSE; + } +else + common->positive_assert = TRUE; +common->positive_assert_quit = NULL; + while (1) { - common->acceptlabel = NULL; + common->accept_label = NULL; common->accept = NULL; altbacktrack.top = NULL; altbacktrack.topbacktracks = NULL; @@ -4255,67 +5763,93 @@ while (1) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); altbacktrack.cc = ccbegin; - compile_trypath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack); + compile_matchingpath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { - common->leavelabel = save_leavelabel; - common->acceptlabel = save_acceptlabel; - common->leave = save_leave; + if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) + { + common->local_exit = save_local_exit; + common->quit_label = save_quit_label; + common->quit = save_quit; + } + common->positive_assert = save_positive_assert; + common->then_trap = save_then_trap; + common->accept_label = save_accept_label; + common->positive_assert_quit = save_positive_assert_quit; common->accept = save_accept; return NULL; } - common->acceptlabel = LABEL(); + common->accept_label = LABEL(); if (common->accept != NULL) - set_jumps(common->accept, common->acceptlabel); + set_jumps(common->accept, common->accept_label); /* Reset stack. */ if (framesize < 0) - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - else { + { + if (framesize == no_frame) + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + else + free_stack(common, extrasize); + if (needs_control_head) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), 0); + } + else + { if ((opcode != OP_ASSERT_NOT && opcode != OP_ASSERTBACK_NOT) || conditional) { - /* We don't need to keep the STR_PTR, only the previous localptr. */ - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_w)); + /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ + OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); + if (needs_control_head) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), 0); } else { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + if (needs_control_head) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), (framesize + 1) * sizeof(sljit_sw)); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); } - } + } if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) { /* We know that STR_PTR was stored on the top of the stack. */ if (conditional) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? sizeof(sljit_sw) : 0); else if (bra == OP_BRAZERO) { if (framesize < 0) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 1) * sizeof(sljit_sw)); else { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_w)); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (framesize + 1) * sizeof(sljit_w)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_sw)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (framesize + extrasize - 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, TMP1, 0); } - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else if (framesize >= 0) { /* For OP_BRA and OP_BRAMINZERO. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_w)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_sw)); } } add_jump(compiler, found, JUMP(SLJIT_JUMP)); - compile_backtrackpath(common, altbacktrack.top); + compile_backtrackingpath(common, altbacktrack.top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { - common->leavelabel = save_leavelabel; - common->acceptlabel = save_acceptlabel; - common->leave = save_leave; + if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) + { + common->local_exit = save_local_exit; + common->quit_label = save_quit_label; + common->quit = save_quit; + } + common->positive_assert = save_positive_assert; + common->then_trap = save_then_trap; + common->accept_label = save_accept_label; + common->positive_assert_quit = save_positive_assert_quit; common->accept = save_accept; return NULL; } @@ -4327,9 +5861,33 @@ while (1) ccbegin = cc; cc += GET(cc, 1); } + +if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) + { + SLJIT_ASSERT(common->positive_assert_quit == NULL); + /* Makes the check less complicated below. */ + common->positive_assert_quit = common->quit; + } + /* None of them matched. */ -if (common->leave != NULL) - set_jumps(common->leave, LABEL()); +if (common->positive_assert_quit != NULL) + { + jump = JUMP(SLJIT_JUMP); + set_jumps(common->positive_assert_quit, LABEL()); + SLJIT_ASSERT(framesize != no_stack); + if (framesize < 0) + OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw)); + else + { + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw)); + } + JUMPHERE(jump); + } + +if (needs_control_head) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(1)); if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) { @@ -4340,23 +5898,27 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) if (framesize < 0) { /* The topmost item should be 0. */ - if (bra == OP_BRAZERO) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - else - free_stack(common, 1); - } - else - { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - /* The topmost item should be 0. */ if (bra == OP_BRAZERO) { - free_stack(common, framesize + 1); + if (extrasize == 2) + free_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else - free_stack(common, framesize + 2); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0); + free_stack(common, extrasize); + } + else + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1)); + /* The topmost item should be 0. */ + if (bra == OP_BRAZERO) + { + free_stack(common, framesize + extrasize - 1); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); + } + else + free_stack(common, framesize + extrasize); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, TMP1, 0); } jump = JUMP(SLJIT_JUMP); if (bra != OP_BRAZERO) @@ -4367,13 +5929,17 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) if (framesize < 0) { /* We know that STR_PTR was stored on the top of the stack. */ - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 1) * sizeof(sljit_sw)); /* Keep the STR_PTR on the top of the stack. */ if (bra == OP_BRAZERO) - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w)); + { + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); + if (extrasize == 2) + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); + } else if (bra == OP_BRAMINZERO) { - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } } @@ -4381,33 +5947,42 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) { if (bra == OP_BRA) { - /* We don't need to keep the STR_PTR, only the previous localptr. */ - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_w)); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0); + /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ + OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (extrasize - 2) * sizeof(sljit_sw)); } else { - /* We don't need to keep the STR_PTR, only the previous localptr. */ - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_w)); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), bra == OP_BRAZERO ? STR_PTR : SLJIT_IMM, 0); + /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ + OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw)); + if (extrasize == 2) + { + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + if (bra == OP_BRAMINZERO) + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); + } + else + { + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), bra == OP_BRAZERO ? STR_PTR : SLJIT_IMM, 0); + } } } if (bra == OP_BRAZERO) { - backtrack->trypath = LABEL(); - sljit_set_label(jump, backtrack->trypath); + backtrack->matchingpath = LABEL(); + SET_LABEL(jump, backtrack->matchingpath); } else if (bra == OP_BRAMINZERO) { - JUMPTO(SLJIT_JUMP, backtrack->trypath); + JUMPTO(SLJIT_JUMP, backtrack->matchingpath); JUMPHERE(brajump); if (framesize >= 0) { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_w)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_sw)); } set_jumps(backtrack->common.topbacktracks, LABEL()); } @@ -4419,30 +5994,34 @@ else { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); if (bra != OP_BRA) + { + if (extrasize == 2) + free_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); + } else - free_stack(common, 1); + free_stack(common, extrasize); } else { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1)); /* The topmost item should be 0. */ if (bra != OP_BRA) { - free_stack(common, framesize + 1); + free_stack(common, framesize + extrasize - 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else - free_stack(common, framesize + 2); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0); + free_stack(common, framesize + extrasize); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, TMP1, 0); } if (bra == OP_BRAZERO) - backtrack->trypath = LABEL(); + backtrack->matchingpath = LABEL(); else if (bra == OP_BRAMINZERO) { - JUMPTO(SLJIT_JUMP, backtrack->trypath); + JUMPTO(SLJIT_JUMP, backtrack->matchingpath); JUMPHERE(brajump); } @@ -4454,121 +6033,89 @@ else } } -common->leavelabel = save_leavelabel; -common->acceptlabel = save_acceptlabel; -common->leave = save_leave; +if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) + { + common->local_exit = save_local_exit; + common->quit_label = save_quit_label; + common->quit = save_quit; + } +common->positive_assert = save_positive_assert; +common->then_trap = save_then_trap; +common->accept_label = save_accept_label; +common->positive_assert_quit = save_positive_assert_quit; common->accept = save_accept; return cc + 1 + LINK_SIZE; } -static sljit_w SLJIT_CALL do_searchovector(sljit_w refno, sljit_w* locals, pcre_uchar *name_table) +static SLJIT_INLINE void match_once_common(compiler_common *common, pcre_uchar ket, int framesize, int private_data_ptr, BOOL has_alternatives, BOOL needs_control_head) { -int condition = FALSE; -pcre_uchar *slotA = name_table; -pcre_uchar *slotB; -sljit_w name_count = locals[LOCALS0 / sizeof(sljit_w)]; -sljit_w name_entry_size = locals[LOCALS1 / sizeof(sljit_w)]; -sljit_w no_capture; -int i; +DEFINE_COMPILER; +int stacksize; -locals += refno & 0xff; -refno >>= 8; -no_capture = locals[1]; - -for (i = 0; i < name_count; i++) +if (framesize < 0) { - if (GET2(slotA, 0) == refno) break; - slotA += name_entry_size; - } - -if (i < name_count) - { - /* Found a name for the number - there can be only one; duplicate names - for different numbers are allowed, but not vice versa. First scan down - for duplicates. */ - - slotB = slotA; - while (slotB > name_table) + if (framesize == no_frame) + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + else { - slotB -= name_entry_size; - if (STRCMP_UC_UC(slotA + IMM2_SIZE, slotB + IMM2_SIZE) == 0) - { - condition = locals[GET2(slotB, 0) << 1] != no_capture; - if (condition) break; - } - else break; + stacksize = needs_control_head ? 1 : 0; + if (ket != OP_KET || has_alternatives) + stacksize++; + free_stack(common, stacksize); } - /* Scan up for duplicates */ - if (!condition) + if (needs_control_head) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), (ket != OP_KET || has_alternatives) ? sizeof(sljit_sw) : 0); + + /* TMP2 which is set here used by OP_KETRMAX below. */ + if (ket == OP_KETRMAX) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), 0); + else if (ket == OP_KETRMIN) { - slotB = slotA; - for (i++; i < name_count; i++) - { - slotB += name_entry_size; - if (STRCMP_UC_UC(slotA + IMM2_SIZE, slotB + IMM2_SIZE) == 0) - { - condition = locals[GET2(slotB, 0) << 1] != no_capture; - if (condition) break; - } - else break; - } + /* Move the STR_PTR to the private_data_ptr. */ + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_MEM1(STACK_TOP), 0); } } -return condition; +else + { + stacksize = (ket != OP_KET || has_alternatives) ? 2 : 1; + OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_IMM, (framesize + stacksize) * sizeof(sljit_sw)); + if (needs_control_head) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), 0); + + if (ket == OP_KETRMAX) + { + /* TMP2 which is set here used by OP_KETRMAX below. */ + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + } + } +if (needs_control_head) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, TMP1, 0); } -static sljit_w SLJIT_CALL do_searchgroups(sljit_w recno, sljit_w* locals, pcre_uchar *name_table) +static SLJIT_INLINE int match_capture_common(compiler_common *common, int stacksize, int offset, int private_data_ptr) { -int condition = FALSE; -pcre_uchar *slotA = name_table; -pcre_uchar *slotB; -sljit_w name_count = locals[LOCALS0 / sizeof(sljit_w)]; -sljit_w name_entry_size = locals[LOCALS1 / sizeof(sljit_w)]; -sljit_w group_num = locals[POSSESSIVE0 / sizeof(sljit_w)]; -int i; +DEFINE_COMPILER; -for (i = 0; i < name_count; i++) +if (common->capture_last_ptr != 0) { - if (GET2(slotA, 0) == recno) break; - slotA += name_entry_size; + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr, SLJIT_IMM, offset >> 1); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); + stacksize++; } - -if (i < name_count) +if (common->optimized_cbracket[offset >> 1] == 0) { - /* Found a name for the number - there can be only one; duplicate - names for different numbers are allowed, but not vice versa. First - scan down for duplicates. */ - - slotB = slotA; - while (slotB > name_table) - { - slotB -= name_entry_size; - if (STRCMP_UC_UC(slotA + IMM2_SIZE, slotB + IMM2_SIZE) == 0) - { - condition = GET2(slotB, 0) == group_num; - if (condition) break; - } - else break; - } - - /* Scan up for duplicates */ - if (!condition) - { - slotB = slotA; - for (i++; i < name_count; i++) - { - slotB += name_entry_size; - if (STRCMP_UC_UC(slotA + IMM2_SIZE, slotB + IMM2_SIZE) == 0) - { - condition = GET2(slotB, 0) == group_num; - if (condition) break; - } - else break; - } - } + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0); + stacksize += 2; } -return condition; +return stacksize; } /* @@ -4625,24 +6172,28 @@ return condition; Or nothing, if trace is unnecessary */ -static pcre_uchar *compile_bracket_trypath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) +static pcre_uchar *compile_bracket_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; pcre_uchar opcode; -int localptr = 0; +int private_data_ptr = 0; int offset = 0; -int stacksize; +int i, stacksize; +int repeat_ptr = 0, repeat_length = 0; +int repeat_type = 0, repeat_count = 0; pcre_uchar *ccbegin; -pcre_uchar *trypath; +pcre_uchar *matchingpath; +pcre_uchar *slot; pcre_uchar bra = OP_BRA; pcre_uchar ket; assert_backtrack *assert; BOOL has_alternatives; +BOOL needs_control_head = FALSE; struct sljit_jump *jump; struct sljit_jump *skip; -struct sljit_label *rmaxlabel = NULL; -struct sljit_jump *braminzerojump = NULL; +struct sljit_label *rmax_label = NULL; +struct sljit_jump *braminzero = NULL; PUSH_BACKTRACK(sizeof(bracket_backtrack), cc, NULL); @@ -4655,35 +6206,36 @@ if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) opcode = *cc; ccbegin = cc; -trypath = ccbegin + 1 + LINK_SIZE; +matchingpath = bracketend(cc) - 1 - LINK_SIZE; +ket = *matchingpath; +if (ket == OP_KET && PRIVATE_DATA(matchingpath) != 0) + { + repeat_ptr = PRIVATE_DATA(matchingpath); + repeat_length = PRIVATE_DATA(matchingpath + 1); + repeat_type = PRIVATE_DATA(matchingpath + 2); + repeat_count = PRIVATE_DATA(matchingpath + 3); + SLJIT_ASSERT(repeat_length != 0 && repeat_type != 0 && repeat_count != 0); + if (repeat_type == OP_UPTO) + ket = OP_KETRMAX; + if (repeat_type == OP_MINUPTO) + ket = OP_KETRMIN; + } if ((opcode == OP_COND || opcode == OP_SCOND) && cc[1 + LINK_SIZE] == OP_DEF) { /* Drop this bracket_backtrack. */ parent->top = backtrack->prev; - return bracketend(cc); + return matchingpath + 1 + LINK_SIZE + repeat_length; } -ket = *(bracketend(cc) - 1 - LINK_SIZE); +matchingpath = ccbegin + 1 + LINK_SIZE; SLJIT_ASSERT(ket == OP_KET || ket == OP_KETRMAX || ket == OP_KETRMIN); SLJIT_ASSERT(!((bra == OP_BRAZERO && ket == OP_KETRMIN) || (bra == OP_BRAMINZERO && ket == OP_KETRMAX))); cc += GET(cc, 1); has_alternatives = *cc == OP_ALT; -if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) - { - has_alternatives = (*trypath == OP_RREF) ? FALSE : TRUE; - if (*trypath == OP_NRREF) - { - stacksize = GET2(trypath, 1); - if (common->currententry == NULL || stacksize == RREF_ANY) - has_alternatives = FALSE; - else if (common->currententry->start == 0) - has_alternatives = stacksize != 0; - else - has_alternatives = stacksize != GET2(common->start, common->currententry->start + 1 + LINK_SIZE); - } - } +if (SLJIT_UNLIKELY(opcode == OP_COND || opcode == OP_SCOND)) + has_alternatives = (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF) ? FALSE : TRUE; if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN)) opcode = OP_SCOND; @@ -4694,24 +6246,32 @@ if (opcode == OP_CBRA || opcode == OP_SCBRA) { /* Capturing brackets has a pre-allocated space. */ offset = GET2(ccbegin, 1 + LINK_SIZE); - localptr = OVECTOR_PRIV(offset); - offset <<= 1; - BACKTRACK_AS(bracket_backtrack)->localptr = localptr; - trypath += IMM2_SIZE; + if (common->optimized_cbracket[offset] == 0) + { + private_data_ptr = OVECTOR_PRIV(offset); + offset <<= 1; + } + else + { + offset <<= 1; + private_data_ptr = OVECTOR(offset); + } + BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr; + matchingpath += IMM2_SIZE; } else if (opcode == OP_ONCE || opcode == OP_SBRA || opcode == OP_SCOND) { /* Other brackets simply allocate the next entry. */ - localptr = PRIV_DATA(ccbegin); - SLJIT_ASSERT(localptr != 0); - BACKTRACK_AS(bracket_backtrack)->localptr = localptr; + private_data_ptr = PRIVATE_DATA(ccbegin); + SLJIT_ASSERT(private_data_ptr != 0); + BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr; if (opcode == OP_ONCE) - BACKTRACK_AS(bracket_backtrack)->u.framesize = get_framesize(common, ccbegin, FALSE); + BACKTRACK_AS(bracket_backtrack)->u.framesize = get_framesize(common, ccbegin, NULL, FALSE, &needs_control_head); } /* Instructions before the first alternative. */ stacksize = 0; -if ((ket == OP_KETRMAX) || (ket == OP_KETRMIN && bra != OP_BRAMINZERO)) +if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO)) stacksize++; if (bra == OP_BRAZERO) stacksize++; @@ -4720,7 +6280,7 @@ if (stacksize > 0) allocate_stack(common, stacksize); stacksize = 0; -if ((ket == OP_KETRMAX) || (ket == OP_KETRMIN && bra != OP_BRAMINZERO)) +if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO)) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); stacksize++; @@ -4736,7 +6296,7 @@ if (bra == OP_BRAMINZERO) if (ket != OP_KETRMIN) { free_stack(common, 1); - braminzerojump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); + braminzero = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); } else { @@ -4750,14 +6310,14 @@ if (bra == OP_BRAMINZERO) /* Checking zero-length iteration. */ if (opcode != OP_ONCE || BACKTRACK_AS(bracket_backtrack)->u.framesize < 0) { - /* When we come from outside, localptr contains the previous STR_PTR. */ - braminzerojump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + /* When we come from outside, private_data_ptr contains the previous STR_PTR. */ + braminzero = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); } else { /* Except when the whole stack frame must be saved. */ - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - braminzerojump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (BACKTRACK_AS(bracket_backtrack)->u.framesize + 1) * sizeof(sljit_w)); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + braminzero = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (BACKTRACK_AS(bracket_backtrack)->u.framesize + 1) * sizeof(sljit_sw)); } JUMPHERE(skip); } @@ -4770,80 +6330,129 @@ if (bra == OP_BRAMINZERO) } } +if (repeat_type != 0) + { + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, SLJIT_IMM, repeat_count); + if (repeat_type == OP_EXACT) + rmax_label = LABEL(); + } + if (ket == OP_KETRMIN) - BACKTRACK_AS(bracket_backtrack)->recursivetrypath = LABEL(); + BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL(); if (ket == OP_KETRMAX) { - rmaxlabel = LABEL(); - if (has_alternatives && opcode != OP_ONCE && opcode < OP_SBRA) - BACKTRACK_AS(bracket_backtrack)->alttrypath = rmaxlabel; + rmax_label = LABEL(); + if (has_alternatives && opcode != OP_ONCE && opcode < OP_SBRA && repeat_type == 0) + BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = rmax_label; } /* Handling capturing brackets and alternatives. */ if (opcode == OP_ONCE) { + stacksize = 0; + if (needs_control_head) + { + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); + stacksize++; + } + if (BACKTRACK_AS(bracket_backtrack)->u.framesize < 0) { - /* Neither capturing brackets nor recursions are not found in the block. */ + /* Neither capturing brackets nor recursions are found in the block. */ if (ket == OP_KETRMIN) { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - allocate_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); - OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w)); - } - else if (ket == OP_KETRMAX || has_alternatives) - { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0); - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); + stacksize += 2; + if (!needs_control_head) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); } else - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0); + { + if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STACK_TOP, 0); + if (ket == OP_KETRMAX || has_alternatives) + stacksize++; + } + + if (stacksize > 0) + allocate_stack(common, stacksize); + + stacksize = 0; + if (needs_control_head) + { + stacksize++; + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); + } + + if (ket == OP_KETRMIN) + { + if (needs_control_head) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); + if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame) + OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, needs_control_head ? (2 * sizeof(sljit_sw)) : sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0); + } + else if (ket == OP_KETRMAX || has_alternatives) + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); } else { - if (ket == OP_KETRMIN || ket == OP_KETRMAX || has_alternatives) + if (ket != OP_KET || has_alternatives) + stacksize++; + + stacksize += BACKTRACK_AS(bracket_backtrack)->u.framesize + 1; + allocate_stack(common, stacksize); + + if (needs_control_head) + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); + + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); + + stacksize = needs_control_head ? 1 : 0; + if (ket != OP_KET || has_alternatives) { - allocate_stack(common, BACKTRACK_AS(bracket_backtrack)->u.framesize + 2); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, -STACK(BACKTRACK_AS(bracket_backtrack)->u.framesize + 1)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - init_frame(common, ccbegin, BACKTRACK_AS(bracket_backtrack)->u.framesize + 1, 2, FALSE); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, TMP2, 0); + stacksize++; + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); } else { - allocate_stack(common, BACKTRACK_AS(bracket_backtrack)->u.framesize + 1); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, -STACK(BACKTRACK_AS(bracket_backtrack)->u.framesize)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); - init_frame(common, ccbegin, BACKTRACK_AS(bracket_backtrack)->u.framesize, 1, FALSE); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, TMP2, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); } + init_frame(common, ccbegin, NULL, BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize, stacksize + 1, FALSE); } } else if (opcode == OP_CBRA || opcode == OP_SCBRA) { /* Saving the previous values. */ - allocate_stack(common, 3); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0); + if (common->optimized_cbracket[offset >> 1] != 0) + { + SLJIT_ASSERT(private_data_ptr == OVECTOR(offset)); + allocate_stack(common, 2); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr + sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STR_PTR, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); + } + else + { + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + allocate_stack(common, 1); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STR_PTR, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); + } } else if (opcode == OP_SBRA || opcode == OP_SCOND) { /* Saving the previous value. */ - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STR_PTR, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); } else if (has_alternatives) @@ -4856,128 +6465,126 @@ else if (has_alternatives) /* Generating code for the first alternative. */ if (opcode == OP_COND || opcode == OP_SCOND) { - if (*trypath == OP_CREF) + if (*matchingpath == OP_CREF) { SLJIT_ASSERT(has_alternatives); add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), - CMP(SLJIT_C_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(GET2(trypath, 1) << 1), SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1))); - trypath += 1 + IMM2_SIZE; + CMP(SLJIT_C_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(GET2(matchingpath, 1) << 1), SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1))); + matchingpath += 1 + IMM2_SIZE; } - else if (*trypath == OP_NCREF) + else if (*matchingpath == OP_DNCREF) { SLJIT_ASSERT(has_alternatives); - stacksize = GET2(trypath, 1); - jump = CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(stacksize << 1), SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STACK_TOP, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, SLJIT_IMM, common->name_count); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, SLJIT_IMM, common->name_entry_size); - OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG1, 0, SLJIT_IMM, (stacksize << 8) | (common->ovector_start / sizeof(sljit_w))); - GET_LOCAL_BASE(SLJIT_TEMPORARY_REG2, 0, 0); - OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, common->name_table); - sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_searchovector)); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1); - add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), CMP(SLJIT_C_EQUAL, SLJIT_TEMPORARY_REG1, 0, SLJIT_IMM, 0)); - - JUMPHERE(jump); - trypath += 1 + IMM2_SIZE; + i = GET2(matchingpath, 1 + IMM2_SIZE); + slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size; + OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(1)); + OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(GET2(slot, 0) << 1), TMP1, 0); + slot += common->name_entry_size; + i--; + while (i-- > 0) + { + OP2(SLJIT_SUB, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(GET2(slot, 0) << 1), TMP1, 0); + OP2(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, STR_PTR, 0); + slot += common->name_entry_size; + } + OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); + add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), JUMP(SLJIT_C_ZERO)); + matchingpath += 1 + 2 * IMM2_SIZE; } - else if (*trypath == OP_RREF || *trypath == OP_NRREF) + else if (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF) { /* Never has other case. */ BACKTRACK_AS(bracket_backtrack)->u.condfailed = NULL; + SLJIT_ASSERT(!has_alternatives); - stacksize = GET2(trypath, 1); - if (common->currententry == NULL) - stacksize = 0; - else if (stacksize == RREF_ANY) - stacksize = 1; - else if (common->currententry->start == 0) - stacksize = stacksize == 0; - else - stacksize = stacksize == GET2(common->start, common->currententry->start + 1 + LINK_SIZE); - - if (*trypath == OP_RREF || stacksize || common->currententry == NULL) + if (*matchingpath == OP_RREF) { - SLJIT_ASSERT(!has_alternatives); - if (stacksize != 0) - trypath += 1 + IMM2_SIZE; + stacksize = GET2(matchingpath, 1); + if (common->currententry == NULL) + stacksize = 0; + else if (stacksize == RREF_ANY) + stacksize = 1; + else if (common->currententry->start == 0) + stacksize = stacksize == 0; else + stacksize = stacksize == (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE); + + if (stacksize != 0) + matchingpath += 1 + IMM2_SIZE; + } + else + { + if (common->currententry == NULL || common->currententry->start == 0) + stacksize = 0; + else + { + stacksize = GET2(matchingpath, 1 + IMM2_SIZE); + slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size; + i = (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE); + while (stacksize > 0) + { + if ((int)GET2(slot, 0) == i) + break; + slot += common->name_entry_size; + stacksize--; + } + } + + if (stacksize != 0) + matchingpath += 1 + 2 * IMM2_SIZE; + } + + /* The stacksize == 0 is a common "else" case. */ + if (stacksize == 0) { if (*cc == OP_ALT) { - trypath = cc + 1 + LINK_SIZE; + matchingpath = cc + 1 + LINK_SIZE; cc += GET(cc, 1); } else - trypath = cc; + matchingpath = cc; } - } - else - { - SLJIT_ASSERT(has_alternatives); - - stacksize = GET2(trypath, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STACK_TOP, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, SLJIT_IMM, common->name_count); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS1, SLJIT_IMM, common->name_entry_size); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, GET2(common->start, common->currententry->start + 1 + LINK_SIZE)); - OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG1, 0, SLJIT_IMM, stacksize); - GET_LOCAL_BASE(SLJIT_TEMPORARY_REG2, 0, 0); - OP1(SLJIT_MOV, SLJIT_TEMPORARY_REG3, 0, SLJIT_IMM, common->name_table); - sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_searchgroups)); - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1); - add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), CMP(SLJIT_C_EQUAL, SLJIT_TEMPORARY_REG1, 0, SLJIT_IMM, 0)); - trypath += 1 + IMM2_SIZE; - } } else { - SLJIT_ASSERT(has_alternatives && *trypath >= OP_ASSERT && *trypath <= OP_ASSERTBACK_NOT); + SLJIT_ASSERT(has_alternatives && *matchingpath >= OP_ASSERT && *matchingpath <= OP_ASSERTBACK_NOT); /* Similar code as PUSH_BACKTRACK macro. */ assert = sljit_alloc_memory(compiler, sizeof(assert_backtrack)); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; memset(assert, 0, sizeof(assert_backtrack)); - assert->common.cc = trypath; + assert->common.cc = matchingpath; BACKTRACK_AS(bracket_backtrack)->u.assert = assert; - trypath = compile_assert_trypath(common, trypath, assert, TRUE); + matchingpath = compile_assert_matchingpath(common, matchingpath, assert, TRUE); } } -compile_trypath(common, trypath, cc, backtrack); +compile_matchingpath(common, matchingpath, cc, backtrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; if (opcode == OP_ONCE) - { - if (BACKTRACK_AS(bracket_backtrack)->u.framesize < 0) - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - /* TMP2 which is set here used by OP_KETRMAX below. */ - if (ket == OP_KETRMAX) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), 0); - else if (ket == OP_KETRMIN) - { - /* Move the STR_PTR to the localptr. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), 0); - } - } - else - { - stacksize = (ket == OP_KETRMIN || ket == OP_KETRMAX || has_alternatives) ? 2 : 1; - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize) * sizeof(sljit_w)); - if (ket == OP_KETRMAX) - { - /* TMP2 which is set here used by OP_KETRMAX below. */ - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - } - } - } + match_once_common(common, ket, BACKTRACK_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head); stacksize = 0; +if (repeat_type == OP_MINUPTO) + { + /* We need to preserve the counter. TMP2 will be used below. */ + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr); + stacksize++; + } if (ket != OP_KET || bra != OP_BRA) stacksize++; +if (offset != 0) + { + if (common->capture_last_ptr != 0) + stacksize++; + if (common->optimized_cbracket[offset >> 1] == 0) + stacksize += 2; + } if (has_alternatives && opcode != OP_ONCE) stacksize++; @@ -4985,72 +6592,102 @@ if (stacksize > 0) allocate_stack(common, stacksize); stacksize = 0; -if (ket != OP_KET) +if (repeat_type == OP_MINUPTO) { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); + /* TMP2 was set above. */ + OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1); stacksize++; } -else if (bra != OP_BRA) + +if (ket != OP_KET || bra != OP_BRA) { - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); + if (ket != OP_KET) + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); + else + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); stacksize++; } +if (offset != 0) + stacksize = match_capture_common(common, stacksize, offset, private_data_ptr); + if (has_alternatives) { if (opcode != OP_ONCE) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); if (ket != OP_KETRMAX) - BACKTRACK_AS(bracket_backtrack)->alttrypath = LABEL(); + BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); } -/* Must be after the trypath label. */ -if (offset != 0) +/* Must be after the matchingpath label. */ +if (offset != 0 && common->optimized_cbracket[offset >> 1] != 0) { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 0), TMP1, 0); } if (ket == OP_KETRMAX) { - if (opcode == OP_ONCE || opcode >= OP_SBRA) + if (repeat_type != 0) { if (has_alternatives) - BACKTRACK_AS(bracket_backtrack)->alttrypath = LABEL(); + BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, SLJIT_IMM, 1); + JUMPTO(SLJIT_C_NOT_ZERO, rmax_label); + /* Drop STR_PTR for greedy plus quantifier. */ + if (opcode != OP_ONCE) + free_stack(common, 1); + } + else if (opcode == OP_ONCE || opcode >= OP_SBRA) + { + if (has_alternatives) + BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); /* Checking zero-length iteration. */ if (opcode != OP_ONCE) { - CMPTO(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STR_PTR, 0, rmaxlabel); + CMPTO(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STR_PTR, 0, rmax_label); /* Drop STR_PTR for greedy plus quantifier. */ if (bra != OP_BRAZERO) free_stack(common, 1); } else /* TMP2 must contain the starting STR_PTR. */ - CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0, rmaxlabel); + CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0, rmax_label); } else - JUMPTO(SLJIT_JUMP, rmaxlabel); - BACKTRACK_AS(bracket_backtrack)->recursivetrypath = LABEL(); + JUMPTO(SLJIT_JUMP, rmax_label); + BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL(); + } + +if (repeat_type == OP_EXACT) + { + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, SLJIT_IMM, 1); + JUMPTO(SLJIT_C_NOT_ZERO, rmax_label); + } +else if (repeat_type == OP_UPTO) + { + /* We need to preserve the counter. */ + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr); + allocate_stack(common, 1); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); } if (bra == OP_BRAZERO) - BACKTRACK_AS(bracket_backtrack)->zerotrypath = LABEL(); + BACKTRACK_AS(bracket_backtrack)->zero_matchingpath = LABEL(); if (bra == OP_BRAMINZERO) { /* This is a backtrack path! (From the viewpoint of OP_BRAMINZERO) */ - JUMPTO(SLJIT_JUMP, ((braminzero_backtrack *)parent)->trypath); - if (braminzerojump != NULL) + JUMPTO(SLJIT_JUMP, ((braminzero_backtrack *)parent)->matchingpath); + if (braminzero != NULL) { - JUMPHERE(braminzerojump); + JUMPHERE(braminzero); /* We need to release the end pointer to perform the backtrack for the zero-length iteration. When framesize is < 0, OP_ONCE will do the release itself. */ if (opcode == OP_ONCE && BACKTRACK_AS(bracket_backtrack)->u.framesize >= 0) { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); } else if (ket == OP_KETRMIN && opcode != OP_ONCE) @@ -5060,28 +6697,33 @@ if (bra == OP_BRAMINZERO) } if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO) - decrease_call_count(common); + count_match(common); /* Skip the other alternatives. */ while (*cc == OP_ALT) cc += GET(cc, 1); cc += 1 + LINK_SIZE; -return cc; + +/* Temporarily encoding the needs_control_head in framesize. */ +if (opcode == OP_ONCE) + BACKTRACK_AS(bracket_backtrack)->u.framesize = (BACKTRACK_AS(bracket_backtrack)->u.framesize << 1) | (needs_control_head ? 1 : 0); +return cc + repeat_length; } -static pcre_uchar *compile_bracketpos_trypath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) +static pcre_uchar *compile_bracketpos_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; pcre_uchar opcode; -int localptr; +int private_data_ptr; int cbraprivptr = 0; +BOOL needs_control_head; int framesize; int stacksize; int offset = 0; BOOL zero = FALSE; pcre_uchar *ccbegin = NULL; -int stack; +int stack; /* Also contains the offset of control head. */ struct sljit_label *loop = NULL; struct jump_list *emptymatch = NULL; @@ -5093,9 +6735,9 @@ if (*cc == OP_BRAPOSZERO) } opcode = *cc; -localptr = PRIV_DATA(cc); -SLJIT_ASSERT(localptr != 0); -BACKTRACK_AS(bracketpos_backtrack)->localptr = localptr; +private_data_ptr = PRIVATE_DATA(cc); +SLJIT_ASSERT(private_data_ptr != 0); +BACKTRACK_AS(bracketpos_backtrack)->private_data_ptr = private_data_ptr; switch(opcode) { case OP_BRAPOS: @@ -5106,6 +6748,9 @@ switch(opcode) case OP_CBRAPOS: case OP_SCBRAPOS: offset = GET2(cc, 1 + LINK_SIZE); + /* This case cannot be optimized in the same was as + normal capturing brackets. */ + SLJIT_ASSERT(common->optimized_cbracket[offset] == 0); cbraprivptr = OVECTOR_PRIV(offset); offset <<= 1; ccbegin = cc + 1 + LINK_SIZE + IMM2_SIZE; @@ -5116,59 +6761,104 @@ switch(opcode) break; } -framesize = get_framesize(common, cc, FALSE); +framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head); BACKTRACK_AS(bracketpos_backtrack)->framesize = framesize; if (framesize < 0) { - stacksize = (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS) ? 2 : 1; + if (offset != 0) + { + stacksize = 2; + if (common->capture_last_ptr != 0) + stacksize++; + } + else + stacksize = 1; + + if (needs_control_head) + stacksize++; if (!zero) stacksize++; + BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize; allocate_stack(common, stacksize); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, STACK_TOP, 0); + if (framesize == no_frame) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STACK_TOP, 0); - if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS) + stack = 0; + if (offset != 0) { + stack = 2; OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); + if (common->capture_last_ptr != 0) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); + if (needs_control_head) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); + if (common->capture_last_ptr != 0) + { + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0); + stack = 3; + } } else + { + if (needs_control_head) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); + stack = 1; + } + if (needs_control_head) + stack++; if (!zero) - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 1); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), SLJIT_IMM, 1); + if (needs_control_head) + { + stack--; + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0); + } } else { stacksize = framesize + 1; if (!zero) stacksize++; - if (opcode == OP_BRAPOS || opcode == OP_SBRAPOS) + if (needs_control_head) + stacksize++; + if (offset == 0) stacksize++; BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize; - allocate_stack(common, stacksize); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, -STACK(stacksize - 1)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP2, 0); + allocate_stack(common, stacksize); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + if (needs_control_head) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); + OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, -STACK(stacksize - 1)); + stack = 0; if (!zero) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 1); + stack = 1; + } + if (needs_control_head) + { + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0); stack++; } - if (opcode == OP_BRAPOS || opcode == OP_SBRAPOS) + if (offset == 0) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), STR_PTR, 0); stack++; } OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP1, 0); - init_frame(common, cc, stacksize - 1, stacksize - framesize, FALSE); + init_frame(common, cc, NULL, stacksize - 1, stacksize - framesize, FALSE); + stack -= 1 + (offset == 0); } -if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS) +if (offset != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr, STR_PTR, 0); loop = LABEL(); @@ -5178,19 +6868,22 @@ while (*cc != OP_KETRPOS) backtrack->topbacktracks = NULL; cc += GET(cc, 1); - compile_trypath(common, ccbegin, cc, backtrack); + compile_matchingpath(common, ccbegin, cc, backtrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; if (framesize < 0) { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + if (framesize == no_frame) + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); - if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS) + if (offset != 0) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr, STR_PTR, 0); + if (common->capture_last_ptr != 0) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr, SLJIT_IMM, offset >> 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0); } else @@ -5208,21 +6901,23 @@ while (*cc != OP_KETRPOS) } else { - if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS) + if (offset != 0) { - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, stacksize * sizeof(sljit_w)); + OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_IMM, stacksize * sizeof(sljit_sw)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr, STR_PTR, 0); + if (common->capture_last_ptr != 0) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr, SLJIT_IMM, offset >> 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0); } else { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - OP2(SLJIT_ADD, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_w)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + OP2(SLJIT_ADD, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); if (opcode == OP_SBRAPOS) - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_w)); - OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_w), STR_PTR, 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw), STR_PTR, 0); } if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS) @@ -5236,34 +6931,38 @@ while (*cc != OP_KETRPOS) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } } + + if (needs_control_head) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack)); + JUMPTO(SLJIT_JUMP, loop); flush_stubs(common); - compile_backtrackpath(common, backtrack->top); + compile_backtrackingpath(common, backtrack->top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; set_jumps(backtrack->topbacktracks, LABEL()); if (framesize < 0) { - if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS) + if (offset != 0) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr); else OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); } else { - if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS) + if (offset != 0) { /* Last alternative. */ if (*cc == OP_KETRPOS) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr); } else { - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_w)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw)); } } @@ -5272,22 +6971,24 @@ while (*cc != OP_KETRPOS) ccbegin = cc + 1 + LINK_SIZE; } +/* We don't have to restore the control head in case of a failed match. */ + backtrack->topbacktracks = NULL; if (!zero) { if (framesize < 0) add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0)); - else /* TMP2 is set to [localptr] above. */ - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(TMP2), (stacksize - 1) * sizeof(sljit_w), SLJIT_IMM, 0)); + else /* TMP2 is set to [private_data_ptr] above. */ + add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(TMP2), (stacksize - 1) * sizeof(sljit_sw), SLJIT_IMM, 0)); } /* None of them matched. */ set_jumps(emptymatch, LABEL()); -decrease_call_count(common); +count_match(common); return cc + 1 + LINK_SIZE; } -static SLJIT_INLINE pcre_uchar *get_iterator_parameters(compiler_common *common, pcre_uchar *cc, pcre_uchar *opcode, pcre_uchar *type, int *arg1, int *arg2, pcre_uchar **end) +static SLJIT_INLINE pcre_uchar *get_iterator_parameters(compiler_common *common, pcre_uchar *cc, pcre_uchar *opcode, pcre_uchar *type, int *max, int *min, pcre_uchar **end) { int class_len; @@ -5323,7 +7024,7 @@ else if (*opcode >= OP_TYPESTAR && *opcode <= OP_TYPEPOSUPTO) } else { - SLJIT_ASSERT(*opcode >= OP_CLASS || *opcode <= OP_XCLASS); + SLJIT_ASSERT(*opcode == OP_CLASS || *opcode == OP_NCLASS || *opcode == OP_XCLASS); *type = *opcode; cc++; class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(pcre_uchar))) : GET(cc, 0); @@ -5334,18 +7035,24 @@ else if (end != NULL) *end = cc + class_len; } + else if (*opcode >= OP_CRPOSSTAR && *opcode <= OP_CRPOSQUERY) + { + *opcode -= OP_CRPOSSTAR - OP_POSSTAR; + if (end != NULL) + *end = cc + class_len; + } else { - SLJIT_ASSERT(*opcode == OP_CRRANGE || *opcode == OP_CRMINRANGE); - *arg1 = GET2(cc, (class_len + IMM2_SIZE)); - *arg2 = GET2(cc, class_len); + SLJIT_ASSERT(*opcode == OP_CRRANGE || *opcode == OP_CRMINRANGE || *opcode == OP_CRPOSRANGE); + *max = GET2(cc, (class_len + IMM2_SIZE)); + *min = GET2(cc, class_len); - if (*arg2 == 0) + if (*min == 0) { - SLJIT_ASSERT(*arg1 != 0); - *opcode = (*opcode == OP_CRRANGE) ? OP_UPTO : OP_MINUPTO; + SLJIT_ASSERT(*max != 0); + *opcode = (*opcode == OP_CRRANGE) ? OP_UPTO : (*opcode == OP_CRMINRANGE ? OP_MINUPTO : OP_POSUPTO); } - if (*arg1 == *arg2) + if (*max == *min) *opcode = OP_EXACT; if (end != NULL) @@ -5356,7 +7063,7 @@ else if (*opcode == OP_UPTO || *opcode == OP_MINUPTO || *opcode == OP_EXACT || *opcode == OP_POSUPTO) { - *arg1 = GET2(cc, 0); + *max = GET2(cc, 0); cc += IMM2_SIZE; } @@ -5379,21 +7086,65 @@ if (end != NULL) return cc; } -static pcre_uchar *compile_iterator_trypath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) +static pcre_uchar *compile_iterator_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; pcre_uchar opcode; pcre_uchar type; -int arg1 = -1, arg2 = -1; +int max = -1, min = -1; pcre_uchar* end; jump_list *nomatch = NULL; struct sljit_jump *jump = NULL; struct sljit_label *label; +int private_data_ptr = PRIVATE_DATA(cc); +int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_LOCALS_REG); +int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr; +int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw); +int tmp_base, tmp_offset; PUSH_BACKTRACK(sizeof(iterator_backtrack), cc, NULL); -cc = get_iterator_parameters(common, cc, &opcode, &type, &arg1, &arg2, &end); +cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &min, &end); + +switch(type) + { + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + case OP_ANY: + case OP_ALLANY: + case OP_ANYBYTE: + case OP_ANYNL: + case OP_NOT_HSPACE: + case OP_HSPACE: + case OP_NOT_VSPACE: + case OP_VSPACE: + case OP_CHAR: + case OP_CHARI: + case OP_NOT: + case OP_NOTI: + case OP_CLASS: + case OP_NCLASS: + tmp_base = TMP3; + tmp_offset = 0; + break; + + default: + SLJIT_ASSERT_STOP(); + /* Fall through. */ + + case OP_EXTUNI: + case OP_XCLASS: + case OP_NOTPROP: + case OP_PROP: + tmp_base = SLJIT_MEM1(SLJIT_LOCALS_REG); + tmp_offset = POSSESSIVE0; + break; + } switch(opcode) { @@ -5403,6 +7154,7 @@ switch(opcode) case OP_CRRANGE: if (type == OP_ANYNL || type == OP_EXTUNI) { + SLJIT_ASSERT(private_data_ptr == 0); if (opcode == OP_STAR || opcode == OP_UPTO) { allocate_stack(common, 2); @@ -5414,22 +7166,24 @@ switch(opcode) allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } + if (opcode == OP_UPTO || opcode == OP_CRRANGE) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 0); label = LABEL(); - compile_char1_trypath(common, type, cc, &backtrack->topbacktracks); + compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks); if (opcode == OP_UPTO || opcode == OP_CRRANGE) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - if (opcode == OP_CRRANGE && arg2 > 0) - CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg2, label); - if (opcode == OP_UPTO || (opcode == OP_CRRANGE && arg1 > 0)) - jump = CMP(SLJIT_C_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, arg1); + if (opcode == OP_CRRANGE && min > 0) + CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, min, label); + if (opcode == OP_UPTO || (opcode == OP_CRRANGE && max > 0)) + jump = CMP(SLJIT_C_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, max); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, TMP1, 0); } + /* We cannot use TMP3 because of this allocate_stack. */ allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); JUMPTO(SLJIT_JUMP, label); @@ -5439,105 +7193,134 @@ switch(opcode) else { if (opcode == OP_PLUS) - compile_char1_trypath(common, type, cc, &backtrack->topbacktracks); - allocate_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1); + compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks); + if (private_data_ptr == 0) + allocate_stack(common, 2); + OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); + if (opcode <= OP_PLUS) + OP1(SLJIT_MOV, base, offset1, STR_PTR, 0); + else + OP1(SLJIT_MOV, base, offset1, SLJIT_IMM, 1); label = LABEL(); - compile_char1_trypath(common, type, cc, &nomatch); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - if (opcode <= OP_PLUS || (opcode == OP_CRRANGE && arg1 == 0)) + compile_char1_matchingpath(common, type, cc, &nomatch); + OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); + if (opcode <= OP_PLUS) + JUMPTO(SLJIT_JUMP, label); + else if (opcode == OP_CRRANGE && max == 0) { - OP2(SLJIT_ADD, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1); + OP2(SLJIT_ADD, base, offset1, base, offset1, SLJIT_IMM, 1); JUMPTO(SLJIT_JUMP, label); } else { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); + OP1(SLJIT_MOV, TMP1, 0, base, offset1); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); - CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg1 + 1, label); + OP1(SLJIT_MOV, base, offset1, TMP1, 0); + CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, max + 1, label); } set_jumps(nomatch, LABEL()); if (opcode == OP_CRRANGE) - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_LESS, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, arg2 + 1)); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_LESS, base, offset1, SLJIT_IMM, min + 1)); + OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); } - BACKTRACK_AS(iterator_backtrack)->trypath = LABEL(); + BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL(); break; case OP_MINSTAR: case OP_MINPLUS: if (opcode == OP_MINPLUS) - compile_char1_trypath(common, type, cc, &backtrack->topbacktracks); - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - BACKTRACK_AS(iterator_backtrack)->trypath = LABEL(); + compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks); + if (private_data_ptr == 0) + allocate_stack(common, 1); + OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); + BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL(); break; case OP_MINUPTO: case OP_CRMINRANGE: - allocate_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1); + if (private_data_ptr == 0) + allocate_stack(common, 2); + OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); + OP1(SLJIT_MOV, base, offset1, SLJIT_IMM, 1); if (opcode == OP_CRMINRANGE) add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP)); - BACKTRACK_AS(iterator_backtrack)->trypath = LABEL(); + BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL(); break; case OP_QUERY: case OP_MINQUERY: - allocate_stack(common, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); + if (private_data_ptr == 0) + allocate_stack(common, 1); + OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); if (opcode == OP_QUERY) - compile_char1_trypath(common, type, cc, &backtrack->topbacktracks); - BACKTRACK_AS(iterator_backtrack)->trypath = LABEL(); + compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks); + BACKTRACK_AS(iterator_backtrack)->matchingpath = LABEL(); break; case OP_EXACT: - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 1); + OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max); label = LABEL(); - compile_char1_trypath(common, type, cc, &backtrack->topbacktracks); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, TMP1, 0); - CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg1 + 1, label); + compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks); + OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + JUMPTO(SLJIT_C_NOT_ZERO, label); break; case OP_POSSTAR: case OP_POSPLUS: case OP_POSUPTO: - if (opcode != OP_POSSTAR) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STR_PTR, 0); + if (opcode == OP_POSPLUS) + compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks); + if (opcode == OP_POSUPTO) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, SLJIT_IMM, max); + OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); label = LABEL(); - compile_char1_trypath(common, type, cc, &nomatch); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STR_PTR, 0); + compile_char1_matchingpath(common, type, cc, &nomatch); + OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); if (opcode != OP_POSUPTO) - { - if (opcode == OP_POSPLUS) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 2); JUMPTO(SLJIT_JUMP, label); - } else { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0); - OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, TMP1, 0); - CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg1 + 1, label); + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, SLJIT_IMM, 1); + JUMPTO(SLJIT_C_NOT_ZERO, label); } set_jumps(nomatch, LABEL()); - if (opcode == OP_POSPLUS) - add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_LESS, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE0, SLJIT_IMM, 2)); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1); + OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset); break; case OP_POSQUERY: - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STR_PTR, 0); - compile_char1_trypath(common, type, cc, &nomatch); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, STR_PTR, 0); + OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); + compile_char1_matchingpath(common, type, cc, &nomatch); + OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); set_jumps(nomatch, LABEL()); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1); + OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset); + break; + + case OP_CRPOSRANGE: + /* Combination of OP_EXACT and OP_POSSTAR or OP_POSUPTO */ + OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, min); + label = LABEL(); + compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks); + OP2(SLJIT_SUB | SLJIT_SET_E, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); + JUMPTO(SLJIT_C_NOT_ZERO, label); + + if (max != 0) + { + SLJIT_ASSERT(max - min > 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, SLJIT_IMM, max - min); + } + OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); + label = LABEL(); + compile_char1_matchingpath(common, type, cc, &nomatch); + OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); + if (max == 0) + JUMPTO(SLJIT_JUMP, label); + else + { + OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, SLJIT_MEM1(SLJIT_LOCALS_REG), POSSESSIVE1, SLJIT_IMM, 1); + JUMPTO(SLJIT_C_NOT_ZERO, label); + } + set_jumps(nomatch, LABEL()); + OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset); break; default: @@ -5545,16 +7328,16 @@ switch(opcode) break; } -decrease_call_count(common); +count_match(common); return end; } -static SLJIT_INLINE pcre_uchar *compile_fail_accept_trypath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) +static SLJIT_INLINE pcre_uchar *compile_fail_accept_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; -PUSH_BACKTRACK(sizeof(bracket_backtrack), cc, NULL); +PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); if (*cc == OP_FAIL) { @@ -5565,54 +7348,133 @@ if (*cc == OP_FAIL) if (*cc == OP_ASSERT_ACCEPT || common->currententry != NULL) { /* No need to check notempty conditions. */ - if (common->acceptlabel == NULL) + if (common->accept_label == NULL) add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP)); else - JUMPTO(SLJIT_JUMP, common->acceptlabel); + JUMPTO(SLJIT_JUMP, common->accept_label); return cc + 1; } -if (common->acceptlabel == NULL) +if (common->accept_label == NULL) add_jump(compiler, &common->accept, CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0))); else - CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), common->acceptlabel); + CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), common->accept_label); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty)); add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart)); -if (common->acceptlabel == NULL) +if (common->accept_label == NULL) add_jump(compiler, &common->accept, CMP(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, 0)); else - CMPTO(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, 0, common->acceptlabel); + CMPTO(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, 0, common->accept_label); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); -if (common->acceptlabel == NULL) +if (common->accept_label == NULL) add_jump(compiler, &common->accept, CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0)); else - CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0, common->acceptlabel); + CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0, common->accept_label); add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP)); return cc + 1; } -static SLJIT_INLINE pcre_uchar *compile_close_trypath(compiler_common *common, pcre_uchar *cc) +static SLJIT_INLINE pcre_uchar *compile_close_matchingpath(compiler_common *common, pcre_uchar *cc) { DEFINE_COMPILER; int offset = GET2(cc, 1); +BOOL optimized_cbracket = common->optimized_cbracket[offset] != 0; /* Data will be discarded anyway... */ if (common->currententry != NULL) return cc + 1 + IMM2_SIZE; -OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR_PRIV(offset)); +if (!optimized_cbracket) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR_PRIV(offset)); offset <<= 1; OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0); +if (!optimized_cbracket) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0); return cc + 1 + IMM2_SIZE; } -static void compile_trypath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, backtrack_common *parent) +static SLJIT_INLINE pcre_uchar *compile_control_verb_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; +pcre_uchar opcode = *cc; +pcre_uchar *ccend = cc + 1; + +if (opcode == OP_PRUNE_ARG || opcode == OP_SKIP_ARG || opcode == OP_THEN_ARG) + ccend += 2 + cc[1]; + +PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); + +if (opcode == OP_SKIP) + { + allocate_stack(common, 1); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); + return ccend; + } + +if (opcode == OP_PRUNE_ARG || opcode == OP_THEN_ARG) + { + OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr, TMP2, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0); + } + +return ccend; +} + +static pcre_uchar then_trap_opcode[1] = { OP_THEN_TRAP }; + +static SLJIT_INLINE void compile_then_trap_matchingpath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, backtrack_common *parent) +{ +DEFINE_COMPILER; +backtrack_common *backtrack; +BOOL needs_control_head; +int size; + +PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc); +common->then_trap = BACKTRACK_AS(then_trap_backtrack); +BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode; +BACKTRACK_AS(then_trap_backtrack)->start = (sljit_sw)(cc - common->start); +BACKTRACK_AS(then_trap_backtrack)->framesize = get_framesize(common, cc, ccend, FALSE, &needs_control_head); + +size = BACKTRACK_AS(then_trap_backtrack)->framesize; +size = 3 + (size < 0 ? 0 : size); + +OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); +allocate_stack(common, size); +if (size > 3) + OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, STACK_TOP, 0, SLJIT_IMM, (size - 3) * sizeof(sljit_sw)); +else + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, STACK_TOP, 0); +OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 1), SLJIT_IMM, BACKTRACK_AS(then_trap_backtrack)->start); +OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 2), SLJIT_IMM, type_then_trap); +OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 3), TMP2, 0); + +size = BACKTRACK_AS(then_trap_backtrack)->framesize; +if (size >= 0) + init_frame(common, cc, ccend, size - 1, 0, FALSE); +} + +static void compile_matchingpath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, backtrack_common *parent) +{ +DEFINE_COMPILER; +backtrack_common *backtrack; +BOOL has_then_trap = FALSE; +then_trap_backtrack *save_then_trap = NULL; + +SLJIT_ASSERT(*ccend == OP_END || (*ccend >= OP_ALT && *ccend <= OP_KETRPOS)); + +if (common->has_then && common->then_offsets[cc - common->start] != 0) + { + SLJIT_ASSERT(*ccend != OP_END && common->control_head_ptr != 0); + has_then_trap = TRUE; + save_then_trap = common->then_trap; + /* Tail item on backtrack. */ + compile_then_trap_matchingpath(common, cc, ccend, parent); + } while (cc < ccend) { @@ -5648,7 +7510,7 @@ while (cc < ccend) case OP_NOT: case OP_NOTI: case OP_REVERSE: - cc = compile_char1_trypath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); + cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); break; case OP_SET_SOM: @@ -5663,9 +7525,9 @@ while (cc < ccend) case OP_CHAR: case OP_CHARI: if (common->mode == JIT_COMPILE) - cc = compile_charn_trypath(common, cc, ccend, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); + cc = compile_charn_matchingpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); else - cc = compile_char1_trypath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); + cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); break; case OP_STAR: @@ -5733,36 +7595,55 @@ while (cc < ccend) case OP_TYPEPOSPLUS: case OP_TYPEPOSQUERY: case OP_TYPEPOSUPTO: - cc = compile_iterator_trypath(common, cc, parent); + cc = compile_iterator_matchingpath(common, cc, parent); break; case OP_CLASS: case OP_NCLASS: - if (cc[1 + (32 / sizeof(pcre_uchar))] >= OP_CRSTAR && cc[1 + (32 / sizeof(pcre_uchar))] <= OP_CRMINRANGE) - cc = compile_iterator_trypath(common, cc, parent); + if (cc[1 + (32 / sizeof(pcre_uchar))] >= OP_CRSTAR && cc[1 + (32 / sizeof(pcre_uchar))] <= OP_CRPOSRANGE) + cc = compile_iterator_matchingpath(common, cc, parent); else - cc = compile_char1_trypath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); + cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); break; -#if defined SUPPORT_UTF || defined COMPILE_PCRE16 +#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case OP_XCLASS: - if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= OP_CRMINRANGE) - cc = compile_iterator_trypath(common, cc, parent); + if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= OP_CRPOSRANGE) + cc = compile_iterator_matchingpath(common, cc, parent); else - cc = compile_char1_trypath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); + cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); break; #endif case OP_REF: case OP_REFI: - if (cc[1 + IMM2_SIZE] >= OP_CRSTAR && cc[1 + IMM2_SIZE] <= OP_CRMINRANGE) - cc = compile_ref_iterator_trypath(common, cc, parent); + if (cc[1 + IMM2_SIZE] >= OP_CRSTAR && cc[1 + IMM2_SIZE] <= OP_CRPOSRANGE) + cc = compile_ref_iterator_matchingpath(common, cc, parent); else - cc = compile_ref_trypath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE); + { + compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE); + cc += 1 + IMM2_SIZE; + } + break; + + case OP_DNREF: + case OP_DNREFI: + if (cc[1 + 2 * IMM2_SIZE] >= OP_CRSTAR && cc[1 + 2 * IMM2_SIZE] <= OP_CRPOSRANGE) + cc = compile_ref_iterator_matchingpath(common, cc, parent); + else + { + compile_dnref_search(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); + compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE); + cc += 1 + 2 * IMM2_SIZE; + } break; case OP_RECURSE: - cc = compile_recurse_trypath(common, cc, parent); + cc = compile_recurse_matchingpath(common, cc, parent); + break; + + case OP_CALLOUT: + cc = compile_callout_matchingpath(common, cc, parent); break; case OP_ASSERT: @@ -5770,7 +7651,7 @@ while (cc < ccend) case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc); - cc = compile_assert_trypath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE); + cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE); break; case OP_BRAMINZERO: @@ -5787,9 +7668,9 @@ while (cc < ccend) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_PTR, 0); } - BACKTRACK_AS(braminzero_backtrack)->trypath = LABEL(); + BACKTRACK_AS(braminzero_backtrack)->matchingpath = LABEL(); if (cc[1] > OP_ASSERTBACK_NOT) - decrease_call_count(common); + count_match(common); break; case OP_ONCE: @@ -5800,16 +7681,16 @@ while (cc < ccend) case OP_SBRA: case OP_SCBRA: case OP_SCOND: - cc = compile_bracket_trypath(common, cc, parent); + cc = compile_bracket_matchingpath(common, cc, parent); break; case OP_BRAZERO: if (cc[1] > OP_ASSERTBACK_NOT) - cc = compile_bracket_trypath(common, cc, parent); + cc = compile_bracket_matchingpath(common, cc, parent); else { PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc); - cc = compile_assert_trypath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE); + cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE); } break; @@ -5818,35 +7699,49 @@ while (cc < ccend) case OP_SBRAPOS: case OP_SCBRAPOS: case OP_BRAPOSZERO: - cc = compile_bracketpos_trypath(common, cc, parent); + cc = compile_bracketpos_matchingpath(common, cc, parent); break; case OP_MARK: PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc); SLJIT_ASSERT(common->mark_ptr != 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr); - allocate_stack(common, 1); + allocate_stack(common, common->has_skip_arg ? 5 : 1); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_w)(cc + 2)); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0), TMP2, 0); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr, TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0); + if (common->has_skip_arg) + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, STACK_TOP, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, type_mark); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), SLJIT_IMM, (sljit_sw)(cc + 2)); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(3), STR_PTR, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); + } cc += 1 + 2 + cc[1]; break; + case OP_PRUNE: + case OP_PRUNE_ARG: + case OP_SKIP: + case OP_SKIP_ARG: + case OP_THEN: + case OP_THEN_ARG: case OP_COMMIT: - PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc); - cc += 1; + cc = compile_control_verb_matchingpath(common, cc, parent); break; case OP_FAIL: case OP_ACCEPT: case OP_ASSERT_ACCEPT: - cc = compile_fail_accept_trypath(common, cc, parent); + cc = compile_fail_accept_matchingpath(common, cc, parent); break; case OP_CLOSE: - cc = compile_close_trypath(common, cc); + cc = compile_close_matchingpath(common, cc); break; case OP_SKIPZERO: @@ -5860,6 +7755,15 @@ while (cc < ccend) if (cc == NULL) return; } + +if (has_then_trap) + { + /* Head item on backtrack. */ + PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc); + BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode; + BACKTRACK_AS(then_trap_backtrack)->then_trap = common->then_trap; + common->then_trap = save_then_trap; + } SLJIT_ASSERT(cc == ccend); } @@ -5867,10 +7771,10 @@ SLJIT_ASSERT(cc == ccend); #undef PUSH_BACKTRACK_NOVALUE #undef BACKTRACK_AS -#define COMPILE_BACKTRACKPATH(current) \ +#define COMPILE_BACKTRACKINGPATH(current) \ do \ { \ - compile_backtrackpath(common, (current)); \ + compile_backtrackingpath(common, (current)); \ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \ return; \ } \ @@ -5878,18 +7782,22 @@ SLJIT_ASSERT(cc == ccend); #define CURRENT_AS(type) ((type *)current) -static void compile_iterator_backtrackpath(compiler_common *common, struct backtrack_common *current) +static void compile_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; pcre_uchar *cc = current->cc; pcre_uchar opcode; pcre_uchar type; -int arg1 = -1, arg2 = -1; +int max = -1, min = -1; struct sljit_label *label = NULL; struct sljit_jump *jump = NULL; jump_list *jumplist = NULL; +int private_data_ptr = PRIVATE_DATA(cc); +int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_LOCALS_REG); +int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr; +int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw); -cc = get_iterator_parameters(common, cc, &opcode, &type, &arg1, &arg2, NULL); +cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &min, NULL); switch(opcode) { @@ -5899,26 +7807,36 @@ switch(opcode) case OP_CRRANGE: if (type == OP_ANYNL || type == OP_EXTUNI) { + SLJIT_ASSERT(private_data_ptr == 0); set_jumps(current->topbacktracks, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); - CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->trypath); + CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->matchingpath); } else { - if (opcode <= OP_PLUS || opcode == OP_UPTO) - arg2 = 0; - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - jump = CMP(SLJIT_C_LESS_EQUAL, TMP1, 0, SLJIT_IMM, arg2 + 1); - OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0, SLJIT_IMM, 1); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + if (opcode == OP_UPTO) + min = 0; + if (opcode <= OP_PLUS) + { + OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); + jump = CMP(SLJIT_C_LESS_EQUAL, STR_PTR, 0, base, offset1); + } + else + { + OP1(SLJIT_MOV, TMP1, 0, base, offset1); + OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); + jump = CMP(SLJIT_C_LESS_EQUAL, TMP1, 0, SLJIT_IMM, min + 1); + OP2(SLJIT_SUB, base, offset1, TMP1, 0, SLJIT_IMM, 1); + } skip_char_back(common); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->trypath); + OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); + JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath); if (opcode == OP_CRRANGE) set_jumps(current->topbacktracks, LABEL()); JUMPHERE(jump); - free_stack(common, 2); + if (private_data_ptr == 0) + free_stack(common, 2); if (opcode == OP_PLUS) set_jumps(current->topbacktracks, LABEL()); } @@ -5926,12 +7844,13 @@ switch(opcode) case OP_MINSTAR: case OP_MINPLUS: - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - compile_char1_trypath(common, type, cc, &jumplist); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); - JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->trypath); + OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); + compile_char1_matchingpath(common, type, cc, &jumplist); + OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); + JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath); set_jumps(jumplist, LABEL()); - free_stack(common, 1); + if (private_data_ptr == 0) + free_stack(common, 1); if (opcode == OP_MINPLUS) set_jumps(current->topbacktracks, LABEL()); break; @@ -5943,52 +7862,56 @@ switch(opcode) label = LABEL(); set_jumps(current->topbacktracks, label); } - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - compile_char1_trypath(common, type, cc, &jumplist); + OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); + compile_char1_matchingpath(common, type, cc, &jumplist); - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); + OP1(SLJIT_MOV, TMP1, 0, base, offset1); + OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); + OP1(SLJIT_MOV, base, offset1, TMP1, 0); if (opcode == OP_CRMINRANGE) - CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg2 + 1, label); + CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, min + 1, label); - if (opcode == OP_CRMINRANGE && arg1 == 0) - JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->trypath); + if (opcode == OP_CRMINRANGE && max == 0) + JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath); else - CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, arg1 + 2, CURRENT_AS(iterator_backtrack)->trypath); + CMPTO(SLJIT_C_LESS, TMP1, 0, SLJIT_IMM, max + 2, CURRENT_AS(iterator_backtrack)->matchingpath); set_jumps(jumplist, LABEL()); - free_stack(common, 2); + if (private_data_ptr == 0) + free_stack(common, 2); break; case OP_QUERY: - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->trypath); + OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); + OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0); + CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->matchingpath); jump = JUMP(SLJIT_JUMP); set_jumps(current->topbacktracks, LABEL()); - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->trypath); + OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); + OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0); + JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath); JUMPHERE(jump); - free_stack(common, 1); + if (private_data_ptr == 0) + free_stack(common, 1); break; case OP_MINQUERY: - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); + OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); + OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0); jump = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); - compile_char1_trypath(common, type, cc, &jumplist); - JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->trypath); + compile_char1_matchingpath(common, type, cc, &jumplist); + JUMPTO(SLJIT_JUMP, CURRENT_AS(iterator_backtrack)->matchingpath); set_jumps(jumplist, LABEL()); JUMPHERE(jump); - free_stack(common, 1); + if (private_data_ptr == 0) + free_stack(common, 1); break; case OP_EXACT: case OP_POSPLUS: + case OP_CRPOSRANGE: set_jumps(current->topbacktracks, LABEL()); break; @@ -6003,33 +7926,40 @@ switch(opcode) } } -static void compile_ref_iterator_backtrackpath(compiler_common *common, struct backtrack_common *current) +static SLJIT_INLINE void compile_ref_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; pcre_uchar *cc = current->cc; +BOOL ref = (*cc == OP_REF || *cc == OP_REFI); pcre_uchar type; -type = cc[1 + IMM2_SIZE]; +type = cc[ref ? 1 + IMM2_SIZE : 1 + 2 * IMM2_SIZE]; + if ((type & 0x1) == 0) { + /* Maximize case. */ set_jumps(current->topbacktracks, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); - CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->trypath); + CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->matchingpath); return; } OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); -CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->trypath); +CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(iterator_backtrack)->matchingpath); set_jumps(current->topbacktracks, LABEL()); -free_stack(common, 2); +free_stack(common, ref ? 2 : 3); } -static void compile_recurse_backtrackpath(compiler_common *common, struct backtrack_common *current) +static SLJIT_INLINE void compile_recurse_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; +if (CURRENT_AS(recurse_backtrack)->inlined_pattern) + compile_backtrackingpath(common, current->top); set_jumps(current->topbacktracks, LABEL()); +if (CURRENT_AS(recurse_backtrack)->inlined_pattern) + return; if (common->has_set_som && common->mark_ptr != 0) { @@ -6047,7 +7977,7 @@ else if (common->has_set_som || common->mark_ptr != 0) } } -static void compile_assert_backtrackpath(compiler_common *common, struct backtrack_common *current) +static void compile_assert_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; pcre_uchar *cc = current->cc; @@ -6074,7 +8004,7 @@ if (CURRENT_AS(assert_backtrack)->framesize < 0) if (bra == OP_BRAZERO) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->trypath); + CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath); free_stack(common, 1); } return; @@ -6085,7 +8015,7 @@ if (bra == OP_BRAZERO) if (*cc == OP_ASSERT_NOT || *cc == OP_ASSERTBACK_NOT) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->trypath); + CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath); free_stack(common, 1); return; } @@ -6095,9 +8025,9 @@ if (bra == OP_BRAZERO) if (*cc == OP_ASSERT || *cc == OP_ASSERTBACK) { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_backtrack)->localptr); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_backtrack)->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_backtrack)->localptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(assert_backtrack)->framesize * sizeof(sljit_w)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(assert_backtrack)->framesize * sizeof(sljit_sw)); set_jumps(current->topbacktracks, LABEL()); } @@ -6107,21 +8037,20 @@ else if (bra == OP_BRAZERO) { /* We know there is enough place on the stack. */ - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); - JUMPTO(SLJIT_JUMP, CURRENT_AS(assert_backtrack)->trypath); + JUMPTO(SLJIT_JUMP, CURRENT_AS(assert_backtrack)->matchingpath); JUMPHERE(brajump); } } -static void compile_bracket_backtrackpath(compiler_common *common, struct backtrack_common *current) +static void compile_bracket_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; -int opcode; +int opcode, stacksize, count; int offset = 0; -int localptr = CURRENT_AS(bracket_backtrack)->localptr; -int stacksize; -int count; +int private_data_ptr = CURRENT_AS(bracket_backtrack)->private_data_ptr; +int repeat_ptr = 0, repeat_type = 0, repeat_count = 0; pcre_uchar *cc = current->cc; pcre_uchar *ccbegin; pcre_uchar *ccprev; @@ -6131,10 +8060,12 @@ pcre_uchar bra = OP_BRA; pcre_uchar ket; assert_backtrack *assert; BOOL has_alternatives; +BOOL needs_control_head = FALSE; struct sljit_jump *brazero = NULL; struct sljit_jump *once = NULL; struct sljit_jump *cond = NULL; -struct sljit_label *rminlabel = NULL; +struct sljit_label *rmin_label = NULL; +struct sljit_label *exact_label = NULL; if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) { @@ -6143,8 +8074,20 @@ if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) } opcode = *cc; +ccbegin = bracketend(cc) - 1 - LINK_SIZE; +ket = *ccbegin; +if (ket == OP_KET && PRIVATE_DATA(ccbegin) != 0) + { + repeat_ptr = PRIVATE_DATA(ccbegin); + repeat_type = PRIVATE_DATA(ccbegin + 2); + repeat_count = PRIVATE_DATA(ccbegin + 3); + SLJIT_ASSERT(repeat_type != 0 && repeat_count != 0); + if (repeat_type == OP_UPTO) + ket = OP_KETRMAX; + if (repeat_type == OP_MINUPTO) + ket = OP_KETRMIN; + } ccbegin = cc; -ket = *(bracketend(ccbegin) - 1 - LINK_SIZE); cc += GET(cc, 1); has_alternatives = *cc == OP_ALT; if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) @@ -6156,6 +8099,24 @@ if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN if (SLJIT_UNLIKELY(opcode == OP_ONCE_NC)) opcode = OP_ONCE; +/* Decoding the needs_control_head in framesize. */ +if (opcode == OP_ONCE) + { + needs_control_head = (CURRENT_AS(bracket_backtrack)->u.framesize & 0x1) != 0; + CURRENT_AS(bracket_backtrack)->u.framesize >>= 1; + } + +if (ket != OP_KET && repeat_type != 0) + { + /* TMP1 is used in OP_KETRMIN below. */ + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + free_stack(common, 1); + if (repeat_type == OP_UPTO) + OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, TMP1, 0, SLJIT_IMM, 1); + else + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, TMP1, 0); + } + if (ket == OP_KETRMAX) { if (bra == OP_BRAZERO) @@ -6170,23 +8131,34 @@ else if (ket == OP_KETRMIN) if (bra != OP_BRAMINZERO) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - if (opcode >= OP_SBRA || opcode == OP_ONCE) + if (repeat_type != 0) + { + /* TMP1 was set a few lines above. */ + CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); + /* Drop STR_PTR for non-greedy plus quantifier. */ + if (opcode != OP_ONCE) + free_stack(common, 1); + } + else if (opcode >= OP_SBRA || opcode == OP_ONCE) { /* Checking zero-length iteration. */ if (opcode != OP_ONCE || CURRENT_AS(bracket_backtrack)->u.framesize < 0) - CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, CURRENT_AS(bracket_backtrack)->recursivetrypath); + CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); else { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (CURRENT_AS(bracket_backtrack)->u.framesize + 1) * sizeof(sljit_w), CURRENT_AS(bracket_backtrack)->recursivetrypath); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), (CURRENT_AS(bracket_backtrack)->u.framesize + 1) * sizeof(sljit_sw), CURRENT_AS(bracket_backtrack)->recursive_matchingpath); } + /* Drop STR_PTR for non-greedy plus quantifier. */ if (opcode != OP_ONCE) free_stack(common, 1); } else - JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->recursivetrypath); + JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); } - rminlabel = LABEL(); + rmin_label = LABEL(); + if (repeat_type != 0) + OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, SLJIT_IMM, 1); } else if (bra == OP_BRAZERO) { @@ -6194,12 +8166,40 @@ else if (bra == OP_BRAZERO) free_stack(common, 1); brazero = CMP(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0); } +else if (repeat_type == OP_EXACT) + { + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, SLJIT_IMM, 1); + exact_label = LABEL(); + } + +if (offset != 0) + { + if (common->capture_last_ptr != 0) + { + SLJIT_ASSERT(common->optimized_cbracket[offset >> 1] == 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr, TMP1, 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2)); + free_stack(common, 3); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP2, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP1, 0); + } + else if (common->optimized_cbracket[offset >> 1] == 0) + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); + free_stack(common, 2); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP2, 0); + } + } if (SLJIT_UNLIKELY(opcode == OP_ONCE)) { if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); } once = JUMP(SLJIT_JUMP); @@ -6252,7 +8252,7 @@ else if (*cc == OP_ALT) cc = ccbegin + GET(ccbegin, 1); } -COMPILE_BACKTRACKPATH(current->top); +COMPILE_BACKTRACKINGPATH(current->top); if (current->topbacktracks) set_jumps(current->topbacktracks, LABEL()); @@ -6265,9 +8265,9 @@ if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) assert = CURRENT_AS(bracket_backtrack)->u.assert; if (assert->framesize >= 0 && (ccbegin[1 + LINK_SIZE] == OP_ASSERT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK)) { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->localptr); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->localptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_w)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_sw)); } cond = JUMP(SLJIT_JUMP); set_jumps(CURRENT_AS(bracket_backtrack)->u.assert->condfailed, LABEL()); @@ -6290,67 +8290,63 @@ if (has_alternatives) current->top = NULL; current->topbacktracks = NULL; current->nextbacktracks = NULL; + /* Conditional blocks always have an additional alternative, even if it is empty. */ if (*cc == OP_ALT) { ccprev = cc + 1 + LINK_SIZE; cc += GET(cc, 1); if (opcode != OP_COND && opcode != OP_SCOND) { - if (localptr != 0 && opcode != OP_ONCE) - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + if (opcode != OP_ONCE) + { + if (private_data_ptr != 0) + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr); + else + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + } else - OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(needs_control_head ? 1 : 0)); } - compile_trypath(common, ccprev, cc, current); + compile_matchingpath(common, ccprev, cc, current); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return; } - /* Instructions after the current alternative is succesfully matched. */ - /* There is a similar code in compile_bracket_trypath. */ + /* Instructions after the current alternative is successfully matched. */ + /* There is a similar code in compile_bracket_matchingpath. */ if (opcode == OP_ONCE) - { - if (CURRENT_AS(bracket_backtrack)->u.framesize < 0) - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); - /* TMP2 which is set here used by OP_KETRMAX below. */ - if (ket == OP_KETRMAX) - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), 0); - else if (ket == OP_KETRMIN) - { - /* Move the STR_PTR to the localptr. */ - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), 0); - } - } - else - { - OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (CURRENT_AS(bracket_backtrack)->u.framesize + 2) * sizeof(sljit_w)); - if (ket == OP_KETRMAX) - { - /* TMP2 which is set here used by OP_KETRMAX below. */ - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - } - } - } + match_once_common(common, ket, CURRENT_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head); stacksize = 0; - if (opcode != OP_ONCE) + if (repeat_type == OP_MINUPTO) + { + /* We need to preserve the counter. TMP2 will be used below. */ + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr); stacksize++; + } if (ket != OP_KET || bra != OP_BRA) stacksize++; + if (offset != 0) + { + if (common->capture_last_ptr != 0) + stacksize++; + if (common->optimized_cbracket[offset >> 1] == 0) + stacksize += 2; + } + if (opcode != OP_ONCE) + stacksize++; - if (stacksize > 0) { - if (opcode != OP_ONCE || CURRENT_AS(bracket_backtrack)->u.framesize >= 0) - allocate_stack(common, stacksize); - else - { - /* We know we have place at least for one item on the top of the stack. */ - SLJIT_ASSERT(stacksize == 1); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w)); - } - } + if (stacksize > 0) + allocate_stack(common, stacksize); stacksize = 0; + if (repeat_type == OP_MINUPTO) + { + /* TMP2 was set above. */ + OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1); + stacksize++; + } + if (ket != OP_KET || bra != OP_BRA) { if (ket != OP_KET) @@ -6360,17 +8356,20 @@ if (has_alternatives) stacksize++; } + if (offset != 0) + stacksize = match_capture_common(common, stacksize, offset, private_data_ptr); + if (opcode != OP_ONCE) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, count++); - if (offset != 0) + if (offset != 0 && ket == OP_KETRMAX && common->optimized_cbracket[offset >> 1] != 0) { - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr); + /* If ket is not OP_KETRMAX, this code path is executed after the jump to alternative_matchingpath. */ + SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 0), TMP1, 0); } - JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->alttrypath); + JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->alternative_matchingpath); if (opcode != OP_ONCE) { @@ -6379,7 +8378,7 @@ if (has_alternatives) jumplist = jumplist->next; } - COMPILE_BACKTRACKPATH(current->top); + COMPILE_BACKTRACKINGPATH(current->top); if (current->topbacktracks) set_jumps(current->topbacktracks, LABEL()); SLJIT_ASSERT(!current->nextbacktracks); @@ -6392,73 +8391,89 @@ if (has_alternatives) SLJIT_ASSERT(opcode == OP_COND || opcode == OP_SCOND); assert = CURRENT_AS(bracket_backtrack)->u.assert; if ((ccbegin[1 + LINK_SIZE] == OP_ASSERT_NOT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK_NOT) && assert->framesize >= 0) - { - OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->localptr); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->localptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_w)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), assert->framesize * sizeof(sljit_sw)); } JUMPHERE(cond); } /* Free the STR_PTR. */ - if (localptr == 0) + if (private_data_ptr == 0) free_stack(common, 1); } if (offset != 0) { /* Using both tmp register is better for instruction scheduling. */ - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP2, 0); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), STACK(2)); - free_stack(common, 3); + if (common->optimized_cbracket[offset >> 1] != 0) + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); + free_stack(common, 2); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP2, 0); + } + else + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + free_stack(common, 1); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, TMP1, 0); + } } else if (opcode == OP_SBRA || opcode == OP_SCOND) { - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), STACK(0)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); } else if (opcode == OP_ONCE) { cc = ccbegin + GET(ccbegin, 1); + stacksize = needs_control_head ? 1 : 0; + if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) { /* Reset head and drop saved frame. */ - stacksize = (ket == OP_KETRMAX || ket == OP_KETRMIN || *cc == OP_ALT) ? 2 : 1; - free_stack(common, CURRENT_AS(bracket_backtrack)->u.framesize + stacksize); + stacksize += CURRENT_AS(bracket_backtrack)->u.framesize + ((ket != OP_KET || *cc == OP_ALT) ? 2 : 1); } else if (ket == OP_KETRMAX || (*cc == OP_ALT && ket != OP_KETRMIN)) { /* The STR_PTR must be released. */ - free_stack(common, 1); + stacksize++; } + free_stack(common, stacksize); JUMPHERE(once); - /* Restore previous localptr */ + /* Restore previous private_data_ptr */ if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracket_backtrack)->u.framesize * sizeof(sljit_w)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracket_backtrack)->u.framesize * sizeof(sljit_sw)); else if (ket == OP_KETRMIN) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); /* See the comment below. */ free_stack(common, 2); - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), private_data_ptr, TMP1, 0); } } -if (ket == OP_KETRMAX) +if (repeat_type == OP_EXACT) + { + OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, SLJIT_IMM, 1); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), repeat_ptr, TMP1, 0); + CMPTO(SLJIT_C_LESS_EQUAL, TMP1, 0, SLJIT_IMM, repeat_count, exact_label); + } +else if (ket == OP_KETRMAX) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); if (bra != OP_BRAZERO) free_stack(common, 1); - CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursivetrypath); + + CMPTO(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); if (bra == OP_BRAZERO) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); - JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zerotrypath); + JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath); JUMPHERE(brazero); free_stack(common, 1); } @@ -6472,7 +8487,7 @@ else if (ket == OP_KETRMIN) affect badly the free_stack(2) above. */ if (opcode != OP_ONCE) free_stack(common, 1); - CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, rminlabel); + CMPTO(SLJIT_C_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, rmin_label); if (opcode == OP_ONCE) free_stack(common, bra == OP_BRAMINZERO ? 2 : 1); else if (bra == OP_BRAMINZERO) @@ -6481,12 +8496,12 @@ else if (ket == OP_KETRMIN) else if (bra == OP_BRAZERO) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zerotrypath); + JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath); JUMPHERE(brazero); } } -static void compile_bracketpos_backtrackpath(compiler_common *common, struct backtrack_common *current) +static SLJIT_INLINE void compile_bracketpos_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; int offset; @@ -6500,14 +8515,18 @@ if (CURRENT_AS(bracketpos_backtrack)->framesize < 0) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0); + if (common->capture_last_ptr != 0) + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), TMP2, 0); + if (common->capture_last_ptr != 0) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr, TMP1, 0); } set_jumps(current->topbacktracks, LABEL()); free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize); return; } -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(bracketpos_backtrack)->localptr); +OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(bracketpos_backtrack)->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); if (current->topbacktracks) @@ -6518,10 +8537,10 @@ if (current->topbacktracks) free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize); JUMPHERE(jump); } -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(bracketpos_backtrack)->localptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracketpos_backtrack)->framesize * sizeof(sljit_w)); +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(bracketpos_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracketpos_backtrack)->framesize * sizeof(sljit_sw)); } -static void compile_braminzero_backtrackpath(compiler_common *common, struct backtrack_common *current) +static SLJIT_INLINE void compile_braminzero_backtrackingpath(compiler_common *common, struct backtrack_common *current) { assert_backtrack backtrack; @@ -6530,24 +8549,118 @@ current->topbacktracks = NULL; current->nextbacktracks = NULL; if (current->cc[1] > OP_ASSERTBACK_NOT) { - /* Manual call of compile_bracket_trypath and compile_bracket_backtrackpath. */ - compile_bracket_trypath(common, current->cc, current); - compile_bracket_backtrackpath(common, current->top); + /* Manual call of compile_bracket_matchingpath and compile_bracket_backtrackingpath. */ + compile_bracket_matchingpath(common, current->cc, current); + compile_bracket_backtrackingpath(common, current->top); } else { memset(&backtrack, 0, sizeof(backtrack)); backtrack.common.cc = current->cc; - backtrack.trypath = CURRENT_AS(braminzero_backtrack)->trypath; - /* Manual call of compile_assert_trypath. */ - compile_assert_trypath(common, current->cc, &backtrack, FALSE); + backtrack.matchingpath = CURRENT_AS(braminzero_backtrack)->matchingpath; + /* Manual call of compile_assert_matchingpath. */ + compile_assert_matchingpath(common, current->cc, &backtrack, FALSE); } SLJIT_ASSERT(!current->nextbacktracks && !current->topbacktracks); } -static void compile_backtrackpath(compiler_common *common, struct backtrack_common *current) +static SLJIT_INLINE void compile_control_verb_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; +pcre_uchar opcode = *current->cc; +struct sljit_label *loop; +struct sljit_jump *jump; + +if (opcode == OP_THEN || opcode == OP_THEN_ARG) + { + if (common->then_trap != NULL) + { + SLJIT_ASSERT(common->control_head_ptr != 0); + + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, type_then_trap); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, common->then_trap->start); + jump = JUMP(SLJIT_JUMP); + + loop = LABEL(); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), -(int)sizeof(sljit_sw)); + JUMPHERE(jump); + CMPTO(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), -(int)(2 * sizeof(sljit_sw)), TMP1, 0, loop); + CMPTO(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), -(int)(3 * sizeof(sljit_sw)), TMP2, 0, loop); + add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP)); + return; + } + else if (common->positive_assert) + { + add_jump(compiler, &common->positive_assert_quit, JUMP(SLJIT_JUMP)); + return; + } + } + +if (common->local_exit) + { + if (common->quit_label == NULL) + add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); + else + JUMPTO(SLJIT_JUMP, common->quit_label); + return; + } + +if (opcode == OP_SKIP_ARG) + { + SLJIT_ASSERT(common->control_head_ptr != 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0, STACK_TOP, 0); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, (sljit_sw)(current->cc + 2)); + sljit_emit_ijump(compiler, SLJIT_CALL2, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_search_mark)); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0); + + OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0); + add_jump(compiler, &common->reset_match, CMP(SLJIT_C_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, -1)); + return; + } + +if (opcode == OP_SKIP) + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); +else + OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_IMM, 0); +add_jump(compiler, &common->reset_match, JUMP(SLJIT_JUMP)); +} + +static SLJIT_INLINE void compile_then_trap_backtrackingpath(compiler_common *common, struct backtrack_common *current) +{ +DEFINE_COMPILER; +struct sljit_jump *jump; +int size; + +if (CURRENT_AS(then_trap_backtrack)->then_trap) + { + common->then_trap = CURRENT_AS(then_trap_backtrack)->then_trap; + return; + } + +size = CURRENT_AS(then_trap_backtrack)->framesize; +size = 3 + (size < 0 ? 0 : size); + +OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(size - 3)); +free_stack(common, size); +jump = JUMP(SLJIT_JUMP); + +set_jumps(CURRENT_AS(then_trap_backtrack)->quit, LABEL()); +/* STACK_TOP is set by THEN. */ +if (CURRENT_AS(then_trap_backtrack)->framesize >= 0) + add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); +OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); +free_stack(common, 3); + +JUMPHERE(jump); +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, TMP1, 0); +} + +static void compile_backtrackingpath(compiler_common *common, struct backtrack_common *current) +{ +DEFINE_COMPILER; +then_trap_backtrack *save_then_trap = common->then_trap; while (current) { @@ -6631,23 +8744,25 @@ while (current) #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: #endif - compile_iterator_backtrackpath(common, current); + compile_iterator_backtrackingpath(common, current); break; case OP_REF: case OP_REFI: - compile_ref_iterator_backtrackpath(common, current); + case OP_DNREF: + case OP_DNREFI: + compile_ref_iterator_backtrackingpath(common, current); break; case OP_RECURSE: - compile_recurse_backtrackpath(common, current); + compile_recurse_backtrackingpath(common, current); break; case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: - compile_assert_backtrackpath(common, current); + compile_assert_backtrackingpath(common, current); break; case OP_ONCE: @@ -6658,14 +8773,14 @@ while (current) case OP_SBRA: case OP_SCBRA: case OP_SCOND: - compile_bracket_backtrackpath(common, current); + compile_bracket_backtrackingpath(common, current); break; case OP_BRAZERO: if (current->cc[1] > OP_ASSERTBACK_NOT) - compile_bracket_backtrackpath(common, current); + compile_bracket_backtrackingpath(common, current); else - compile_assert_backtrackpath(common, current); + compile_assert_backtrackingpath(common, current); break; case OP_BRAPOS: @@ -6673,39 +8788,60 @@ while (current) case OP_SBRAPOS: case OP_SCBRAPOS: case OP_BRAPOSZERO: - compile_bracketpos_backtrackpath(common, current); + compile_bracketpos_backtrackingpath(common, current); break; case OP_BRAMINZERO: - compile_braminzero_backtrackpath(common, current); + compile_braminzero_backtrackingpath(common, current); break; case OP_MARK: - OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - free_stack(common, 1); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0)); + if (common->has_skip_arg) + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); + free_stack(common, common->has_skip_arg ? 5 : 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr, TMP1, 0); + if (common->has_skip_arg) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, TMP2, 0); + break; + + case OP_THEN: + case OP_THEN_ARG: + case OP_PRUNE: + case OP_PRUNE_ARG: + case OP_SKIP: + case OP_SKIP_ARG: + compile_control_verb_backtrackingpath(common, current); break; case OP_COMMIT: - OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH); - if (common->leavelabel == NULL) - add_jump(compiler, &common->leave, JUMP(SLJIT_JUMP)); + if (!common->local_exit) + OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH); + if (common->quit_label == NULL) + add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); else - JUMPTO(SLJIT_JUMP, common->leavelabel); + JUMPTO(SLJIT_JUMP, common->quit_label); break; + case OP_CALLOUT: case OP_FAIL: case OP_ACCEPT: case OP_ASSERT_ACCEPT: set_jumps(current->topbacktracks, LABEL()); break; + case OP_THEN_TRAP: + /* A virtual opcode for then traps. */ + compile_then_trap_backtrackingpath(common, current); + break; + default: SLJIT_ASSERT_STOP(); break; } current = current->prev; } +common->then_trap = save_then_trap; } static SLJIT_INLINE void compile_recurse(compiler_common *common) @@ -6714,40 +8850,44 @@ 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); -int localsize = get_localsize(common, ccbegin, ccend); -int framesize = get_framesize(common, cc, TRUE); +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); int alternativesize; -BOOL needsframe; +BOOL needs_frame; backtrack_common altbacktrack; -struct sljit_label *save_leavelabel = common->leavelabel; -jump_list *save_leave = common->leave; struct sljit_jump *jump; +/* Recurse captures then. */ +common->then_trap = NULL; + SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA || *cc == OP_CBRAPOS || *cc == OP_SCBRA || *cc == OP_SCBRAPOS); -needsframe = framesize >= 0; -if (!needsframe) +needs_frame = framesize >= 0; +if (!needs_frame) framesize = 0; alternativesize = *(cc + GET(cc, 1)) == OP_ALT ? 1 : 0; -SLJIT_ASSERT(common->currententry->entry == NULL && common->recursive_head != 0); +SLJIT_ASSERT(common->currententry->entry == NULL && common->recursive_head_ptr != 0); common->currententry->entry = LABEL(); set_jumps(common->currententry->calls, common->currententry->entry); sljit_emit_fast_enter(compiler, TMP2, 0); -allocate_stack(common, localsize + framesize + alternativesize); -OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(localsize + framesize + alternativesize - 1), TMP2, 0); -copy_locals(common, ccbegin, ccend, TRUE, localsize + framesize + alternativesize, framesize + alternativesize); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->recursive_head, STACK_TOP, 0); -if (needsframe) - init_frame(common, cc, framesize + alternativesize - 1, alternativesize, TRUE); +allocate_stack(common, private_data_size + framesize + alternativesize); +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) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_IMM, 0); +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->recursive_head_ptr, STACK_TOP, 0); +if (needs_frame) + init_frame(common, cc, NULL, framesize + alternativesize - 1, alternativesize, TRUE); if (alternativesize > 0) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); memset(&altbacktrack, 0, sizeof(backtrack_common)); -common->leavelabel = NULL; -common->acceptlabel = NULL; -common->leave = NULL; +common->quit_label = NULL; +common->accept_label = NULL; +common->quit = NULL; common->accept = NULL; altbacktrack.cc = ccbegin; cc += GET(cc, 1); @@ -6759,23 +8899,15 @@ while (1) if (altbacktrack.cc != ccbegin) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); - compile_trypath(common, altbacktrack.cc, cc, &altbacktrack); + compile_matchingpath(common, altbacktrack.cc, cc, &altbacktrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - { - common->leavelabel = save_leavelabel; - common->leave = save_leave; return; - } add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP)); - compile_backtrackpath(common, altbacktrack.top); + compile_backtrackingpath(common, altbacktrack.top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) - { - common->leavelabel = save_leavelabel; - common->leave = save_leave; return; - } set_jumps(altbacktrack.topbacktracks, LABEL()); if (*cc != OP_ALT) @@ -6784,36 +8916,59 @@ while (1) altbacktrack.cc = cc + 1 + LINK_SIZE; cc += GET(cc, 1); } -/* None of them matched. */ -if (common->leave != NULL) - set_jumps(common->leave, LABEL()); +/* None of them matched. */ OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0); jump = JUMP(SLJIT_JUMP); -set_jumps(common->accept, LABEL()); -OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->recursive_head); -if (needsframe) +if (common->quit != NULL) { - OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_w)); + set_jumps(common->quit, LABEL()); + OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->recursive_head_ptr); + if (needs_frame) + { + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); + add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); + } + OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0); + common->quit = NULL; + add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); + } + +set_jumps(common->accept, LABEL()); +OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->recursive_head_ptr); +if (needs_frame) + { + OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); - OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_w)); + OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); } OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 1); JUMPHERE(jump); -copy_locals(common, ccbegin, ccend, FALSE, localsize + framesize + alternativesize, framesize + alternativesize); -free_stack(common, localsize + framesize + alternativesize); -OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), sizeof(sljit_w)); -OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->recursive_head, TMP2, 0); +if (common->quit != NULL) + set_jumps(common->quit, LABEL()); +copy_private_data(common, ccbegin, ccend, FALSE, private_data_size + framesize + alternativesize, framesize + alternativesize, needs_control_head); +free_stack(common, private_data_size + framesize + alternativesize); +if (needs_control_head) + { + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), 2 * sizeof(sljit_sw)); + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), sizeof(sljit_sw)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->recursive_head_ptr, TMP1, 0); + OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, TMP2, 0); + } +else + { + OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), sizeof(sljit_sw)); + OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->recursive_head_ptr, TMP2, 0); + } sljit_emit_fast_return(compiler, SLJIT_MEM1(STACK_TOP), 0); - -common->leavelabel = save_leavelabel; -common->leave = save_leave; } -#undef COMPILE_BACKTRACKPATH +#undef COMPILE_BACKTRACKINGPATH #undef CURRENT_AS void @@ -6825,17 +8980,21 @@ compiler_common common_data; compiler_common *common = &common_data; const pcre_uint8 *tables = re->tables; pcre_study_data *study; -int localsize; +int private_data_size; pcre_uchar *ccend; executable_functions *functions; void *executable_func; sljit_uw executable_size; -struct sljit_label *mainloop = NULL; -struct sljit_label *empty_match_found; -struct sljit_label *empty_match_backtrack; +struct sljit_label *mainloop_label = NULL; +struct sljit_label *continue_match_label; +struct sljit_label *empty_match_found_label; +struct sljit_label *empty_match_backtrack_label; +struct sljit_label *reset_match_label; struct sljit_jump *jump; +struct sljit_jump *minlength_check_failed = NULL; struct sljit_jump *reqbyte_notfound = NULL; struct sljit_jump *empty_match; +struct sljit_label *quit_label; SLJIT_ASSERT((extra->flags & PCRE_EXTRA_STUDY_DATA) != 0); study = extra->study_data; @@ -6849,14 +9008,14 @@ rootbacktrack.cc = (pcre_uchar *)re + re->name_table_offset + re->name_count * r common->start = rootbacktrack.cc; common->fcc = tables + fcc_offset; -common->lcc = (sljit_w)(tables + lcc_offset); +common->lcc = (sljit_sw)(tables + lcc_offset); common->mode = mode; common->nltype = NLTYPE_FIXED; switch(re->options & PCRE_NEWLINE_BITS) { case 0: /* Compile-time default */ - switch (NEWLINE) + switch(NEWLINE) { case -1: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break; case -2: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break; @@ -6884,13 +9043,14 @@ else #endif } common->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; -common->ctypes = (sljit_w)(tables + ctypes_offset); -common->name_table = (sljit_w)((pcre_uchar *)re + re->name_table_offset); +common->ctypes = (sljit_sw)(tables + ctypes_offset); +common->digits[0] = -2; +common->name_table = ((pcre_uchar *)re) + re->name_table_offset; common->name_count = re->name_count; common->name_entry_size = re->name_entry_size; common->jscript_compat = (re->options & PCRE_JAVASCRIPT_COMPAT) != 0; #ifdef SUPPORT_UTF -/* PCRE_UTF16 has the same value as PCRE_UTF8. */ +/* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */ common->utf = (re->options & PCRE_UTF8) != 0; #ifdef SUPPORT_UCP common->use_ucp = (re->options & PCRE_UCP) != 0; @@ -6899,87 +9059,161 @@ common->use_ucp = (re->options & PCRE_UCP) != 0; ccend = bracketend(rootbacktrack.cc); /* Calculate the local space size on the stack. */ -common->ovector_start = CALL_LIMIT + sizeof(sljit_w); +common->ovector_start = LIMIT_MATCH + sizeof(sljit_sw); +common->optimized_cbracket = (pcre_uint8 *)SLJIT_MALLOC(re->top_bracket + 1); +if (!common->optimized_cbracket) + return; +#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 1 +memset(common->optimized_cbracket, 0, re->top_bracket + 1); +#else +memset(common->optimized_cbracket, 1, re->top_bracket + 1); +#endif SLJIT_ASSERT(*rootbacktrack.cc == OP_BRA && ccend[-(1 + LINK_SIZE)] == OP_KET); -localsize = get_localspace(common, rootbacktrack.cc, ccend); -if (localsize < 0) +#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 2 +common->capture_last_ptr = common->ovector_start; +common->ovector_start += sizeof(sljit_sw); +#endif +if (!check_opcode_types(common, rootbacktrack.cc, ccend)) + { + SLJIT_FREE(common->optimized_cbracket); return; + } /* Checking flags and updating ovector_start. */ if (mode == JIT_COMPILE && (re->flags & PCRE_REQCHSET) != 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0) { common->req_char_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_w); + common->ovector_start += sizeof(sljit_sw); } if (mode != JIT_COMPILE) { common->start_used_ptr = common->ovector_start; - common->ovector_start += sizeof(sljit_w); + common->ovector_start += sizeof(sljit_sw); if (mode == JIT_PARTIAL_SOFT_COMPILE) { common->hit_start = common->ovector_start; - common->ovector_start += sizeof(sljit_w); + common->ovector_start += 2 * sizeof(sljit_sw); + } + else + { + SLJIT_ASSERT(mode == JIT_PARTIAL_HARD_COMPILE); + common->needs_start_ptr = TRUE; } } if ((re->options & PCRE_FIRSTLINE) != 0) { common->first_line_end = common->ovector_start; - common->ovector_start += sizeof(sljit_w); + common->ovector_start += sizeof(sljit_sw); } +#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD +common->control_head_ptr = 1; +#endif +if (common->control_head_ptr != 0) + { + common->control_head_ptr = common->ovector_start; + common->ovector_start += sizeof(sljit_sw); + } +if (common->needs_start_ptr && common->has_set_som) + { + /* Saving the real start pointer is necessary. */ + common->start_ptr = common->ovector_start; + common->ovector_start += sizeof(sljit_sw); + } +else + common->needs_start_ptr = FALSE; /* Aligning ovector to even number of sljit words. */ -if ((common->ovector_start & sizeof(sljit_w)) != 0) - common->ovector_start += sizeof(sljit_w); +if ((common->ovector_start & sizeof(sljit_sw)) != 0) + common->ovector_start += sizeof(sljit_sw); + +if (common->start_ptr == 0) + common->start_ptr = OVECTOR(0); + +/* Capturing brackets cannot be optimized if callouts are allowed. */ +if (common->capture_last_ptr != 0) + memset(common->optimized_cbracket, 0, re->top_bracket + 1); SLJIT_ASSERT(!(common->req_char_ptr != 0 && common->start_used_ptr != 0)); -common->cbraptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_w); -localsize += common->cbraptr + (re->top_bracket + 1) * sizeof(sljit_w); -if (localsize > SLJIT_MAX_LOCAL_SIZE) +common->cbra_ptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_sw); + +common->private_data_ptrs = (int *)SLJIT_MALLOC((ccend - rootbacktrack.cc) * sizeof(sljit_si)); +if (!common->private_data_ptrs) + { + SLJIT_FREE(common->optimized_cbracket); return; -common->localptrs = (int *)SLJIT_MALLOC((ccend - rootbacktrack.cc) * sizeof(int)); -if (!common->localptrs) + } +memset(common->private_data_ptrs, 0, (ccend - rootbacktrack.cc) * sizeof(int)); + +private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw); +set_private_data_ptrs(common, &private_data_size, ccend); +if (private_data_size > SLJIT_MAX_LOCAL_SIZE) + { + SLJIT_FREE(common->private_data_ptrs); + SLJIT_FREE(common->optimized_cbracket); return; -memset(common->localptrs, 0, (ccend - rootbacktrack.cc) * sizeof(int)); -set_localptrs(common, common->cbraptr + (re->top_bracket + 1) * sizeof(sljit_w), ccend); + } + +if (common->has_then) + { + common->then_offsets = (pcre_uint8 *)SLJIT_MALLOC(ccend - rootbacktrack.cc); + if (!common->then_offsets) + { + SLJIT_FREE(common->optimized_cbracket); + SLJIT_FREE(common->private_data_ptrs); + return; + } + memset(common->then_offsets, 0, ccend - rootbacktrack.cc); + set_then_offsets(common, rootbacktrack.cc, NULL); + } compiler = sljit_create_compiler(); if (!compiler) { - SLJIT_FREE(common->localptrs); + SLJIT_FREE(common->optimized_cbracket); + SLJIT_FREE(common->private_data_ptrs); + if (common->has_then) + SLJIT_FREE(common->then_offsets); return; } common->compiler = compiler; /* Main pcre_jit_exec entry. */ -sljit_emit_enter(compiler, 1, 5, 5, localsize); +sljit_emit_enter(compiler, 1, 5, 5, private_data_size); /* Register init. */ reset_ovector(common, (re->top_bracket + 1) * 2); if (common->req_char_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->req_char_ptr, SLJIT_TEMPORARY_REG1, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->req_char_ptr, SLJIT_SCRATCH_REG1, 0); OP1(SLJIT_MOV, ARGUMENTS, 0, SLJIT_SAVED_REG1, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_SAVED_REG1, 0); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, end)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack)); -OP1(SLJIT_MOV_SI, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, calllimit)); +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)); -OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CALL_LIMIT, TMP1, 0); +OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LIMIT_MATCH, TMP1, 0); if (mode == JIT_PARTIAL_SOFT_COMPILE) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, -1); +if (common->mark_ptr != 0) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr, SLJIT_IMM, 0); +if (common->control_head_ptr != 0) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->control_head_ptr, SLJIT_IMM, 0); /* Main part of the matching */ if ((re->options & PCRE_ANCHORED) == 0) { - mainloop = mainloop_entry(common, (re->flags & PCRE_HASCRORLF) != 0, (re->options & PCRE_FIRSTLINE) != 0); + mainloop_label = mainloop_entry(common, (re->flags & PCRE_HASCRORLF) != 0, (re->options & PCRE_FIRSTLINE) != 0); + continue_match_label = LABEL(); /* Forward search if possible. */ if ((re->options & PCRE_NO_START_OPTIMIZE) == 0) { - if ((re->flags & PCRE_FIRSTSET) != 0) + if (mode == JIT_COMPILE && fast_forward_first_n_chars(common, (re->options & PCRE_FIRSTLINE) != 0)) + { /* Do nothing */ } + else if ((re->flags & PCRE_FIRSTSET) != 0) fast_forward_first_char(common, (pcre_uchar)re->first_char, (re->flags & PCRE_FCH_CASELESS) != 0, (re->options & PCRE_FIRSTLINE) != 0); else if ((re->flags & PCRE_STARTLINE) != 0) fast_forward_newline(common, (re->options & PCRE_FIRSTLINE) != 0); @@ -6987,69 +9221,99 @@ if ((re->options & PCRE_ANCHORED) == 0) fast_forward_start_bits(common, (sljit_uw)study->start_bits, (re->options & PCRE_FIRSTLINE) != 0); } } +else + continue_match_label = LABEL(); + +if (mode == JIT_COMPILE && study->minlength > 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0) + { + OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH); + OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(study->minlength)); + minlength_check_failed = CMP(SLJIT_C_GREATER, TMP2, 0, STR_END, 0); + } if (common->req_char_ptr != 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); -if (common->mark_ptr != 0) - OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->mark_ptr, SLJIT_IMM, 0); +OP1(SLJIT_MOV, COUNT_MATCH, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LIMIT_MATCH); +if (common->capture_last_ptr != 0) + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->capture_last_ptr, SLJIT_IMM, -1); + +if (common->needs_start_ptr) + { + SLJIT_ASSERT(common->start_ptr != OVECTOR(0)); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_ptr, STR_PTR, 0); + } +else + SLJIT_ASSERT(common->start_ptr == OVECTOR(0)); + /* Copy the beginning of the string. */ if (mode == JIT_PARTIAL_SOFT_COMPILE) { - jump = CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, 0); + jump = CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, -1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_used_ptr, STR_PTR, 0); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start + sizeof(sljit_sw), STR_PTR, 0); JUMPHERE(jump); } else if (mode == JIT_PARTIAL_HARD_COMPILE) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_used_ptr, STR_PTR, 0); -compile_trypath(common, rootbacktrack.cc, ccend, &rootbacktrack); +compile_matchingpath(common, rootbacktrack.cc, ccend, &rootbacktrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { sljit_free_compiler(compiler); - SLJIT_FREE(common->localptrs); + SLJIT_FREE(common->optimized_cbracket); + SLJIT_FREE(common->private_data_ptrs); + if (common->has_then) + SLJIT_FREE(common->then_offsets); return; } empty_match = CMP(SLJIT_C_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0)); -empty_match_found = LABEL(); +empty_match_found_label = LABEL(); -common->acceptlabel = LABEL(); +common->accept_label = LABEL(); if (common->accept != NULL) - set_jumps(common->accept, common->acceptlabel); + set_jumps(common->accept, common->accept_label); /* This means we have a match. Update the ovector. */ copy_ovector(common, re->top_bracket + 1); -common->leavelabel = LABEL(); -if (common->leave != NULL) - set_jumps(common->leave, common->leavelabel); +common->quit_label = common->forced_quit_label = LABEL(); +if (common->quit != NULL) + set_jumps(common->quit, common->quit_label); +if (common->forced_quit != NULL) + set_jumps(common->forced_quit, common->forced_quit_label); +if (minlength_check_failed != NULL) + SET_LABEL(minlength_check_failed, common->forced_quit_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, common->leavelabel); + return_with_partial_match(common, common->quit_label); } -empty_match_backtrack = LABEL(); -compile_backtrackpath(common, rootbacktrack.top); +empty_match_backtrack_label = LABEL(); +compile_backtrackingpath(common, rootbacktrack.top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { sljit_free_compiler(compiler); - SLJIT_FREE(common->localptrs); + SLJIT_FREE(common->optimized_cbracket); + SLJIT_FREE(common->private_data_ptrs); + if (common->has_then) + SLJIT_FREE(common->then_offsets); return; } SLJIT_ASSERT(rootbacktrack.prev == NULL); +reset_match_label = LABEL(); if (mode == JIT_PARTIAL_SOFT_COMPILE) { /* Update hit_start only in the first time. */ - jump = CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, -1); + jump = CMP(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_used_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_used_ptr, SLJIT_IMM, -1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, TMP1, 0); @@ -7057,35 +9321,20 @@ if (mode == JIT_PARTIAL_SOFT_COMPILE) } /* Check we have remaining characters. */ -OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0)); +if ((re->options & PCRE_ANCHORED) == 0 && (re->options & PCRE_FIRSTLINE) != 0) + { + SLJIT_ASSERT(common->first_line_end != 0); + OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end); + } + +OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->start_ptr); if ((re->options & PCRE_ANCHORED) == 0) { if ((re->options & PCRE_FIRSTLINE) == 0) - { - if (mode == JIT_COMPILE && study != NULL && study->minlength > 1 && (re->options & PCRE_NO_START_OPTIMIZE) == 0) - { - OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(study->minlength + 1)); - CMPTO(SLJIT_C_LESS_EQUAL, TMP1, 0, STR_END, 0, mainloop); - } - else - CMPTO(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0, mainloop); - } + CMPTO(SLJIT_C_LESS, STR_PTR, 0, STR_END, 0, mainloop_label); else - { - SLJIT_ASSERT(common->first_line_end != 0); - if (mode == JIT_COMPILE && study != NULL && study->minlength > 1 && (re->options & PCRE_NO_START_OPTIMIZE) == 0) - { - OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(study->minlength + 1)); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, STR_END, 0); - COND_VALUE(SLJIT_MOV, TMP2, 0, SLJIT_C_GREATER); - OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end); - COND_VALUE(SLJIT_OR | SLJIT_SET_E, TMP2, 0, SLJIT_C_GREATER_EQUAL); - JUMPTO(SLJIT_C_ZERO, mainloop); - } - else - CMPTO(SLJIT_C_LESS, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), common->first_line_end, mainloop); - } + CMPTO(SLJIT_C_LESS, STR_PTR, 0, TMP1, 0, mainloop_label); } /* No more remaining characters. */ @@ -7093,24 +9342,26 @@ if (reqbyte_notfound != NULL) JUMPHERE(reqbyte_notfound); if (mode == JIT_PARTIAL_SOFT_COMPILE) - CMPTO(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, 0, common->partialmatchlabel); + CMPTO(SLJIT_C_NOT_EQUAL, SLJIT_MEM1(SLJIT_LOCALS_REG), common->hit_start, SLJIT_IMM, -1, common->partialmatchlabel); OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH); -JUMPTO(SLJIT_JUMP, common->leavelabel); +JUMPTO(SLJIT_JUMP, common->quit_label); flush_stubs(common); JUMPHERE(empty_match); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty)); -CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_backtrack); +CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_backtrack_label); OP1(SLJIT_MOV_UB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart)); -CMPTO(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_found); +CMPTO(SLJIT_C_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_found_label); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); -CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found); -JUMPTO(SLJIT_JUMP, empty_match_backtrack); +CMPTO(SLJIT_C_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found_label); +JUMPTO(SLJIT_JUMP, empty_match_backtrack_label); common->currententry = common->entries; +common->local_exit = TRUE; +quit_label = common->quit_label; while (common->currententry != NULL) { /* Might add new entries. */ @@ -7118,12 +9369,17 @@ while (common->currententry != NULL) if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { sljit_free_compiler(compiler); - SLJIT_FREE(common->localptrs); + SLJIT_FREE(common->optimized_cbracket); + SLJIT_FREE(common->private_data_ptrs); + if (common->has_then) + SLJIT_FREE(common->then_offsets); return; } flush_stubs(common); common->currententry = common->currententry->next; } +common->local_exit = FALSE; +common->quit_label = quit_label; /* Allocating stack, returns with PCRE_ERROR_JIT_STACKLIMIT if fails. */ /* This is a (really) rare case. */ @@ -7149,12 +9405,12 @@ sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS0); 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, common->leavelabel); +JUMPTO(SLJIT_JUMP, common->quit_label); /* Call limit reached. */ set_jumps(common->calllimit, LABEL()); OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_MATCHLIMIT); -JUMPTO(SLJIT_JUMP, common->leavelabel); +JUMPTO(SLJIT_JUMP, common->quit_label); if (common->revertframes != NULL) { @@ -7191,20 +9447,30 @@ if (common->caselesscmp != NULL) set_jumps(common->caselesscmp, LABEL()); do_caselesscmp(common); } +if (common->reset_match != NULL) + { + set_jumps(common->reset_match, LABEL()); + do_reset_match(common, (re->top_bracket + 1) * 2); + CMPTO(SLJIT_C_GREATER, STR_PTR, 0, TMP1, 0, continue_match_label); + OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0); + JUMPTO(SLJIT_JUMP, reset_match_label); + } #ifdef SUPPORT_UTF +#ifndef COMPILE_PCRE32 if (common->utfreadchar != NULL) { set_jumps(common->utfreadchar, LABEL()); do_utfreadchar(common); } +#endif /* !COMPILE_PCRE32 */ #ifdef COMPILE_PCRE8 if (common->utfreadtype8 != NULL) { set_jumps(common->utfreadtype8, LABEL()); do_utfreadtype8(common); } -#endif #endif /* COMPILE_PCRE8 */ +#endif /* SUPPORT_UTF */ #ifdef SUPPORT_UCP if (common->getucd != NULL) { @@ -7213,7 +9479,11 @@ if (common->getucd != NULL) } #endif -SLJIT_FREE(common->localptrs); +SLJIT_FREE(common->optimized_cbracket); +SLJIT_FREE(common->private_data_ptrs); +if (common->has_then) + SLJIT_FREE(common->then_offsets); + executable_func = sljit_generate_code(compiler); executable_size = sljit_get_generated_code_size(compiler); sljit_free_compiler(compiler); @@ -7225,6 +9495,15 @@ if ((extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 && extra->executable_jit != functions = (executable_functions *)extra->executable_jit; else { + /* Note: If your memory-checker has flagged the allocation below as a + * memory leak, it is probably because you either forgot to call + * pcre_free_study() (or pcre16_free_study()) on the pcre_extra (or + * pcre16_extra) object, or you called said function after having + * cleared the PCRE_EXTRA_EXECUTABLE_JIT bit from the "flags" field + * of the object. (The function will only free the JIT data if the + * bit remains set, as the bit indicates that the pointer to the data + * is valid.) + */ functions = SLJIT_MALLOC(sizeof(executable_functions)); if (functions == NULL) { @@ -7234,6 +9513,8 @@ else return; } memset(functions, 0, sizeof(executable_functions)); + functions->top_bracket = (re->top_bracket + 1) * 2; + functions->limit_match = (re->flags & PCRE_MLSET) != 0 ? re->limit_match : 0; extra->executable_jit = functions; extra->flags |= PCRE_EXTRA_EXECUTABLE_JIT; } @@ -7248,12 +9529,12 @@ union { void* executable_func; jit_function call_executable_func; } convert_executable_func; -pcre_uint8 local_area[LOCAL_SPACE_SIZE]; +pcre_uint8 local_space[MACHINE_STACK_SIZE]; struct sljit_stack local_stack; -local_stack.top = (sljit_w)&local_area; +local_stack.top = (sljit_sw)&local_space; local_stack.base = local_stack.top; -local_stack.limit = local_stack.base + LOCAL_SPACE_SIZE; +local_stack.limit = local_stack.base + MACHINE_STACK_SIZE; local_stack.max_limit = local_stack.limit; arguments->stack = &local_stack; convert_executable_func.executable_func = executable_func; @@ -7261,8 +9542,8 @@ return convert_executable_func.call_executable_func(arguments); } int -PRIV(jit_exec)(const REAL_PCRE *re, const PUBL(extra) *extra_data, const pcre_uchar *subject, - int length, int start_offset, int options, int *offsets, int offsetcount) +PRIV(jit_exec)(const PUBL(extra) *extra_data, const pcre_uchar *subject, + int length, int start_offset, int options, int *offsets, int offset_count) { executable_functions *functions = (executable_functions *)extra_data->executable_jit; union { @@ -7270,7 +9551,7 @@ union { jit_function call_executable_func; } convert_executable_func; jit_arguments arguments; -int maxoffsetcount; +int max_offset_count; int retval; int mode = JIT_COMPILE; @@ -7280,34 +9561,37 @@ else if ((options & PCRE_PARTIAL_SOFT) != 0) mode = JIT_PARTIAL_SOFT_COMPILE; if (functions->executable_funcs[mode] == NULL) - return PCRE_ERROR_NULL; + return PCRE_ERROR_JIT_BADOPTION; /* Sanity checks should be handled by pcre_exec. */ -arguments.stack = NULL; arguments.str = subject + start_offset; arguments.begin = subject; arguments.end = subject + length; arguments.mark_ptr = NULL; /* JIT decreases this value less frequently than the interpreter. */ -arguments.calllimit = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : extra_data->match_limit; +arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (pcre_uint32)(extra_data->match_limit); +if (functions->limit_match != 0 && functions->limit_match < arguments.limit_match) + arguments.limit_match = functions->limit_match; arguments.notbol = (options & PCRE_NOTBOL) != 0; arguments.noteol = (options & PCRE_NOTEOL) != 0; arguments.notempty = (options & PCRE_NOTEMPTY) != 0; arguments.notempty_atstart = (options & PCRE_NOTEMPTY_ATSTART) != 0; arguments.offsets = offsets; +arguments.callout_data = (extra_data->flags & PCRE_EXTRA_CALLOUT_DATA) != 0 ? extra_data->callout_data : NULL; +arguments.real_offset_count = offset_count; -/* pcre_exec() rounds offsetcount to a multiple of 3, and then uses only 2/3 of +/* pcre_exec() rounds offset_count to a multiple of 3, and then uses only 2/3 of the output vector for storing captured strings, with the remainder used as workspace. We don't need the workspace here. For compatibility, we limit the number of captured strings in the same way as pcre_exec(), so that the user gets the same result with and without JIT. */ -if (offsetcount != 2) - offsetcount = ((offsetcount - (offsetcount % 3)) * 2) / 3; -maxoffsetcount = (re->top_bracket + 1) * 2; -if (offsetcount > maxoffsetcount) - offsetcount = maxoffsetcount; -arguments.offsetcount = offsetcount; +if (offset_count != 2) + offset_count = ((offset_count - (offset_count % 3)) * 2) / 3; +max_offset_count = functions->top_bracket; +if (offset_count > max_offset_count) + offset_count = max_offset_count; +arguments.offset_count = offset_count; if (functions->callback) arguments.stack = (struct sljit_stack *)functions->callback(functions->userdata); @@ -7322,7 +9606,90 @@ else retval = convert_executable_func.call_executable_func(&arguments); } -if (retval * 2 > offsetcount) +if (retval * 2 > offset_count) + retval = 0; +if ((extra_data->flags & PCRE_EXTRA_MARK) != 0) + *(extra_data->mark) = arguments.mark_ptr; + +return retval; +} + +#if defined COMPILE_PCRE8 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre_jit_exec(const pcre *argument_re, const pcre_extra *extra_data, + PCRE_SPTR subject, int length, int start_offset, int options, + int *offsets, int offset_count, pcre_jit_stack *stack) +#elif defined COMPILE_PCRE16 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre16_jit_exec(const pcre16 *argument_re, const pcre16_extra *extra_data, + PCRE_SPTR16 subject, int length, int start_offset, int options, + int *offsets, int offset_count, pcre16_jit_stack *stack) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_jit_exec(const pcre32 *argument_re, const pcre32_extra *extra_data, + PCRE_SPTR32 subject, int length, int start_offset, int options, + int *offsets, int offset_count, pcre32_jit_stack *stack) +#endif +{ +pcre_uchar *subject_ptr = (pcre_uchar *)subject; +executable_functions *functions = (executable_functions *)extra_data->executable_jit; +union { + void* executable_func; + jit_function call_executable_func; +} convert_executable_func; +jit_arguments arguments; +int max_offset_count; +int retval; +int mode = JIT_COMPILE; + +SLJIT_UNUSED_ARG(argument_re); + +/* Plausibility checks */ +if ((options & ~PUBLIC_JIT_EXEC_OPTIONS) != 0) return PCRE_ERROR_JIT_BADOPTION; + +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_JIT_BADOPTION; + +/* Sanity checks should be handled by pcre_exec. */ +arguments.stack = (struct sljit_stack *)stack; +arguments.str = subject_ptr + start_offset; +arguments.begin = subject_ptr; +arguments.end = subject_ptr + length; +arguments.mark_ptr = NULL; +/* JIT decreases this value less frequently than the interpreter. */ +arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (pcre_uint32)(extra_data->match_limit); +if (functions->limit_match != 0 && functions->limit_match < arguments.limit_match) + arguments.limit_match = functions->limit_match; +arguments.notbol = (options & PCRE_NOTBOL) != 0; +arguments.noteol = (options & PCRE_NOTEOL) != 0; +arguments.notempty = (options & PCRE_NOTEMPTY) != 0; +arguments.notempty_atstart = (options & PCRE_NOTEMPTY_ATSTART) != 0; +arguments.offsets = offsets; +arguments.callout_data = (extra_data->flags & PCRE_EXTRA_CALLOUT_DATA) != 0 ? extra_data->callout_data : NULL; +arguments.real_offset_count = offset_count; + +/* pcre_exec() rounds offset_count to a multiple of 3, and then uses only 2/3 of +the output vector for storing captured strings, with the remainder used as +workspace. We don't need the workspace here. For compatibility, we limit the +number of captured strings in the same way as pcre_exec(), so that the user +gets the same result with and without JIT. */ + +if (offset_count != 2) + offset_count = ((offset_count - (offset_count % 3)) * 2) / 3; +max_offset_count = functions->top_bracket; +if (offset_count > max_offset_count) + offset_count = max_offset_count; +arguments.offset_count = offset_count; + +convert_executable_func.executable_func = functions->executable_funcs[mode]; +retval = convert_executable_func.call_executable_func(&arguments); + +if (retval * 2 > offset_count) retval = 0; if ((extra_data->flags & PCRE_EXTRA_MARK) != 0) *(extra_data->mark) = arguments.mark_ptr; @@ -7360,12 +9727,15 @@ PRIV(jit_get_target)(void) return sljit_get_platform_name(); } -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DECL pcre_jit_stack * pcre_jit_stack_alloc(int startsize, int maxsize) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DECL pcre16_jit_stack * pcre16_jit_stack_alloc(int startsize, int maxsize) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DECL pcre32_jit_stack * +pcre32_jit_stack_alloc(int startsize, int maxsize) #endif { if (startsize < 1 || maxsize < 1) @@ -7377,23 +9747,29 @@ maxsize = (maxsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1); return (PUBL(jit_stack)*)sljit_allocate_stack(startsize, maxsize); } -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *stack) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *stack) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DECL void +pcre32_jit_stack_free(pcre32_jit_stack *stack) #endif { sljit_free_stack((struct sljit_stack *)stack); } -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *extra, pcre_jit_callback callback, void *userdata) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *extra, pcre16_jit_callback callback, void *userdata) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DECL void +pcre32_assign_jit_stack(pcre32_extra *extra, pcre32_jit_callback callback, void *userdata) #endif { executable_functions *functions; @@ -7407,17 +9783,34 @@ if (extra != NULL && } } +#if defined COMPILE_PCRE8 +PCRE_EXP_DECL void +pcre_jit_free_unused_memory(void) +#elif defined COMPILE_PCRE16 +PCRE_EXP_DECL void +pcre16_jit_free_unused_memory(void) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DECL void +pcre32_jit_free_unused_memory(void) +#endif +{ +sljit_free_unused_memory_exec(); +} + #else /* SUPPORT_JIT */ /* These are dummy functions to avoid linking errors when JIT support is not being compiled. */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DECL pcre_jit_stack * pcre_jit_stack_alloc(int startsize, int maxsize) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DECL pcre16_jit_stack * pcre16_jit_stack_alloc(int startsize, int maxsize) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DECL pcre32_jit_stack * +pcre32_jit_stack_alloc(int startsize, int maxsize) #endif { (void)startsize; @@ -7425,23 +9818,29 @@ pcre16_jit_stack_alloc(int startsize, int maxsize) return NULL; } -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *stack) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *stack) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DECL void +pcre32_jit_stack_free(pcre32_jit_stack *stack) #endif { (void)stack; } -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *extra, pcre_jit_callback callback, void *userdata) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *extra, pcre16_jit_callback callback, void *userdata) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DECL void +pcre32_assign_jit_stack(pcre32_extra *extra, pcre32_jit_callback callback, void *userdata) #endif { (void)extra; @@ -7449,6 +9848,19 @@ pcre16_assign_jit_stack(pcre16_extra *extra, pcre16_jit_callback callback, void (void)userdata; } +#if defined COMPILE_PCRE8 +PCRE_EXP_DECL void +pcre_jit_free_unused_memory(void) +#elif defined COMPILE_PCRE16 +PCRE_EXP_DECL void +pcre16_jit_free_unused_memory(void) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DECL void +pcre32_jit_free_unused_memory(void) +#endif +{ +} + #endif /* End of pcre_jit_compile.c */ diff --git a/src/3rd/pcre/pcremktb.c b/src/3rd/pcre/pcremktb.c index 8bb753907e..fdcd4072ff 100644 --- a/src/3rd/pcre/pcremktb.c +++ b/src/3rd/pcre/pcremktb.c @@ -66,12 +66,15 @@ Arguments: none Returns: pointer to the contiguous block of data */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 const unsigned char * pcre_maketables(void) -#else +#elif defined COMPILE_PCRE16 const unsigned char * pcre16_maketables(void) +#elif defined COMPILE_PCRE32 +const unsigned char * +pcre32_maketables(void) #endif { unsigned char *yield, *p; @@ -95,13 +98,17 @@ for (i = 0; i < 256; i++) *p++ = tolower(i); for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i); /* Then the character class tables. Don't try to be clever and save effort on -exclusive ones - in some locales things may be different. Note that the table -for "space" includes everything "isspace" gives, including VT in the default -locale. This makes it work for the POSIX class [:space:]. Note also that it is -possible for a character to be alnum or alpha without being lower or upper, -such as "male and female ordinals" (\xAA and \xBA) in the fr_FR locale (at -least under Debian Linux's locales as of 12/2005). So we must test for alnum -specially. */ +exclusive ones - in some locales things may be different. + +Note that the table for "space" includes everything "isspace" gives, including +VT in the default locale. This makes it work for the POSIX class [:space:]. +From release 8.34 is is also correct for Perl space, because Perl added VT at +release 5.18. + +Note also that it is possible for a character to be alnum or alpha without +being lower or upper, such as "male and female ordinals" (\xAA and \xBA) in the +fr_FR locale (at least under Debian Linux's locales as of 12/2005). So we must +test for alnum specially. */ memset(p, 0, cbit_length); for (i = 0; i < 256; i++) @@ -120,14 +127,15 @@ for (i = 0; i < 256; i++) } p += cbit_length; -/* Finally, the character type table. In this, we exclude VT from the white -space chars, because Perl doesn't recognize it as such for \s and for comments -within regexes. */ +/* Finally, the character type table. In this, we used to exclude VT from the +white space chars, because Perl didn't recognize it as such for \s and for +comments within regexes. However, Perl changed at release 5.18, so PCRE changed +at release 8.34. */ for (i = 0; i < 256; i++) { int x = 0; - if (i != 0x0b && isspace(i)) x += ctype_space; + if (isspace(i)) x += ctype_space; if (isalpha(i)) x += ctype_letter; if (isdigit(i)) x += ctype_digit; if (isxdigit(i)) x += ctype_xdigit; diff --git a/src/3rd/pcre/pcrenewl.c b/src/3rd/pcre/pcrenewl.c index 2c8b1ac8ef..fea6d9b46d 100644 --- a/src/3rd/pcre/pcrenewl.c +++ b/src/3rd/pcre/pcrenewl.c @@ -76,7 +76,7 @@ BOOL PRIV(is_newline)(PCRE_PUCHAR ptr, int type, PCRE_PUCHAR endptr, int *lenptr, BOOL utf) { -int c; +pcre_uint32 c; (void)utf; #ifdef SUPPORT_UTF if (utf) @@ -87,11 +87,13 @@ else #endif /* SUPPORT_UTF */ c = *ptr; +/* Note that this function is called only for ANY or ANYCRLF. */ + if (type == NLTYPE_ANYCRLF) switch(c) { - case 0x000a: *lenptr = 1; return TRUE; /* LF */ - case 0x000d: *lenptr = (ptr < endptr - 1 && ptr[1] == 0x0a)? 2 : 1; - return TRUE; /* CR */ + case CHAR_LF: *lenptr = 1; return TRUE; + case CHAR_CR: *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1; + return TRUE; default: return FALSE; } @@ -99,20 +101,29 @@ if (type == NLTYPE_ANYCRLF) switch(c) else switch(c) { - case 0x000a: /* LF */ - case 0x000b: /* VT */ - case 0x000c: *lenptr = 1; return TRUE; /* FF */ - case 0x000d: *lenptr = (ptr < endptr - 1 && ptr[1] == 0x0a)? 2 : 1; - return TRUE; /* CR */ +#ifdef EBCDIC + case CHAR_NEL: +#endif + case CHAR_LF: + case CHAR_VT: + case CHAR_FF: *lenptr = 1; return TRUE; + + case CHAR_CR: + *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1; + return TRUE; + +#ifndef EBCDIC #ifdef COMPILE_PCRE8 - case 0x0085: *lenptr = utf? 2 : 1; return TRUE; /* NEL */ + case CHAR_NEL: *lenptr = utf? 2 : 1; return TRUE; case 0x2028: /* LS */ case 0x2029: *lenptr = 3; return TRUE; /* PS */ -#else - case 0x0085: /* NEL */ +#else /* COMPILE_PCRE16 || COMPILE_PCRE32 */ + case CHAR_NEL: case 0x2028: /* LS */ case 0x2029: *lenptr = 1; return TRUE; /* PS */ -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE8 */ +#endif /* Not EBCDIC */ + default: return FALSE; } } @@ -140,7 +151,7 @@ BOOL PRIV(was_newline)(PCRE_PUCHAR ptr, int type, PCRE_PUCHAR startptr, int *lenptr, BOOL utf) { -int c; +pcre_uint32 c; (void)utf; ptr--; #ifdef SUPPORT_UTF @@ -153,30 +164,45 @@ else #endif /* SUPPORT_UTF */ c = *ptr; +/* Note that this function is called only for ANY or ANYCRLF. */ + if (type == NLTYPE_ANYCRLF) switch(c) { - case 0x000a: *lenptr = (ptr > startptr && ptr[-1] == 0x0d)? 2 : 1; - return TRUE; /* LF */ - case 0x000d: *lenptr = 1; return TRUE; /* CR */ + case CHAR_LF: + *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1; + return TRUE; + + case CHAR_CR: *lenptr = 1; return TRUE; default: return FALSE; } +/* NLTYPE_ANY */ + else switch(c) { - case 0x000a: *lenptr = (ptr > startptr && ptr[-1] == 0x0d)? 2 : 1; - return TRUE; /* LF */ - case 0x000b: /* VT */ - case 0x000c: /* FF */ - case 0x000d: *lenptr = 1; return TRUE; /* CR */ + case CHAR_LF: + *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1; + return TRUE; + +#ifdef EBCDIC + case CHAR_NEL: +#endif + case CHAR_VT: + case CHAR_FF: + case CHAR_CR: *lenptr = 1; return TRUE; + +#ifndef EBCDIC #ifdef COMPILE_PCRE8 - case 0x0085: *lenptr = utf? 2 : 1; return TRUE; /* NEL */ - case 0x2028: /* LS */ - case 0x2029: *lenptr = 3; return TRUE; /* PS */ -#else - case 0x0085: /* NEL */ + case CHAR_NEL: *lenptr = utf? 2 : 1; return TRUE; + case 0x2028: /* LS */ + case 0x2029: *lenptr = 3; return TRUE; /* PS */ +#else /* COMPILE_PCRE16 || COMPILE_PCRE32 */ + case CHAR_NEL: case 0x2028: /* LS */ case 0x2029: *lenptr = 1; return TRUE; /* PS */ -#endif /* COMPILE_PCRE8 */ +#endif /* COMPILE_PCRE8 */ +#endif /* NotEBCDIC */ + default: return FALSE; } } diff --git a/src/3rd/pcre/pcreoutf.c b/src/3rd/pcre/pcreoutf.c index a552557b93..0b7ec3f90b 100644 --- a/src/3rd/pcre/pcreoutf.c +++ b/src/3rd/pcre/pcreoutf.c @@ -45,15 +45,16 @@ character value into a UTF8 string. */ #include "config.h" #endif -#include "pcreinal.h" +#define COMPILE_PCRE8 +#include "pcreinal.h" /************************************************* * Convert character value to UTF-8 * *************************************************/ /* This function takes an integer value in the range 0 - 0x10ffff -and encodes it as a UTF-8 character in 1 to 6 pcre_uchars. +and encodes it as a UTF-8 character in 1 to 4 pcre_uchars. Arguments: cvalue the character value @@ -62,6 +63,7 @@ Arguments: Returns: number of characters placed in the buffer */ +unsigned int PRIV(ord2utf)(pcre_uint32 cvalue, pcre_uchar *buffer) { @@ -69,11 +71,6 @@ PRIV(ord2utf)(pcre_uint32 cvalue, pcre_uchar *buffer) register int i, j; -/* Checking invalid cvalue character, encoded as invalid UTF-16 character. -Should never happen in practice. */ -if ((cvalue & 0xf800) == 0xd800 || cvalue >= 0x110000) - cvalue = 0xfffe; - for (i = 0; i < PRIV(utf8_table1_size); i++) if ((int)cvalue <= PRIV(utf8_table1)[i]) break; buffer += i; diff --git a/src/3rd/pcre/pcreprni.c b/src/3rd/pcre/pcreprni.c index 3cb4a63b18..56653135cf 100644 --- a/src/3rd/pcre/pcreprni.c +++ b/src/3rd/pcre/pcreprni.c @@ -78,10 +78,13 @@ having a separate .h file just for this. */ #ifdef PCRE_INCLUDED static /* Keep the following function as private. */ #endif -#ifdef COMPILE_PCRE8 + +#if defined COMPILE_PCRE8 void pcre_printint(pcre *external_re, FILE *f, BOOL print_lengths); -#else +#elif defined COMPILE_PCRE16 void pcre16_printint(pcre *external_re, FILE *f, BOOL print_lengths); +#elif defined COMPILE_PCRE32 +void pcre32_printint(pcre *external_re, FILE *f, BOOL print_lengths); #endif /* Macro that decides whether a character should be output as a literal or in @@ -111,26 +114,28 @@ static const pcre_uint8 priv_OP_lengths[] = { OP_LENGTHS }; * Print single- or multi-byte character * *************************************************/ -static int +static unsigned int print_char(FILE *f, pcre_uchar *ptr, BOOL utf) { -int c = *ptr; +pcre_uint32 c = *ptr; #ifndef SUPPORT_UTF (void)utf; /* Avoid compiler warning */ -if (PRINTABLE(c)) fprintf(f, "%c", c); -else if (c <= 0xff) fprintf(f, "\\x%02x", c); +if (PRINTABLE(c)) fprintf(f, "%c", (char)c); +else if (c <= 0x80) fprintf(f, "\\x%02x", c); else fprintf(f, "\\x{%x}", c); return 0; #else -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 if (!utf || (c & 0xc0) != 0xc0) { - if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02x", c); + if (PRINTABLE(c)) fprintf(f, "%c", (char)c); + else if (c < 0x80) fprintf(f, "\\x%02x", c); + else fprintf(f, "\\x{%02x}", c); return 0; } else @@ -160,15 +165,13 @@ else return a; } -#else - -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 if (!utf || (c & 0xfc00) != 0xd800) { - if (PRINTABLE(c)) fprintf(f, "%c", c); - else if (c <= 0xff) fprintf(f, "\\x%02x", c); - else fprintf(f, "\\x{%x}", c); + if (PRINTABLE(c)) fprintf(f, "%c", (char)c); + else if (c <= 0x80) fprintf(f, "\\x%02x", c); + else fprintf(f, "\\x{%02x}", c); return 0; } else @@ -188,9 +191,25 @@ else return 1; } -#endif /* COMPILE_PCRE16 */ +#elif defined COMPILE_PCRE32 -#endif /* COMPILE_PCRE8 */ +if (!utf || (c & 0xfffff800u) != 0xd800u) + { + if (PRINTABLE(c)) fprintf(f, "%c", (char)c); + else if (c <= 0x80) fprintf(f, "\\x%02x", c); + else fprintf(f, "\\x{%x}", c); + return 0; + } +else + { + /* This is a check for malformed UTF-32; it should only occur if the sanity + check has been turned off. Rather than swallow a surrogate, just stop if + we hit one. Print it with \X instead of \x as an indication. */ + fprintf(f, "\\X{%x}", c); + return 0; + } + +#endif /* COMPILE_PCRE[8|16|32] */ #endif /* SUPPORT_UTF */ } @@ -204,7 +223,7 @@ print_puchar(FILE *f, PCRE_PUCHAR ptr) { while (*ptr != '\0') { - register int c = *ptr++; + register pcre_uint32 c = *ptr++; if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c); } } @@ -214,7 +233,7 @@ while (*ptr != '\0') *************************************************/ static const char * -get_ucpname(int ptype, int pvalue) +get_ucpname(unsigned int ptype, unsigned int pvalue) { #ifdef SUPPORT_UCP int i; @@ -231,6 +250,40 @@ return (ptype == pvalue)? "??" : "??"; } +/************************************************* +* Print Unicode property value * +*************************************************/ + +/* "Normal" properties can be printed from tables. The PT_CLIST property is a +pseudo-property that contains a pointer to a list of case-equivalent +characters. This is used only when UCP support is available and UTF mode is +selected. It should never occur otherwise, but just in case it does, have +something ready to print. */ + +static void +print_prop(FILE *f, pcre_uchar *code, const char *before, const char *after) +{ +if (code[1] != PT_CLIST) + { + fprintf(f, "%s%s %s%s", before, priv_OP_names[*code], get_ucpname(code[1], + code[2]), after); + } +else + { + const char *not = (*code == OP_PROP)? "" : "not "; +#ifndef SUPPORT_UCP + fprintf(f, "%s%sclist %d%s", before, not, code[2], after); +#else + const pcre_uint32 *p = PRIV(ucd_caseless_sets) + code[2]; + fprintf (f, "%s%sclist", before, not); + while (*p < NOTACHAR) fprintf(f, " %04x", *p++); + fprintf(f, "%s", after); +#endif + } +} + + + /************************************************* * Print compiled regex * @@ -245,12 +298,15 @@ written that do not depend on the value of LINK_SIZE. */ #ifdef PCRE_INCLUDED static /* Keep the following function as private. */ #endif -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 void pcre_printint(pcre *external_re, FILE *f, BOOL print_lengths) -#else +#elif defined COMPILE_PCRE16 void pcre16_printint(pcre *external_re, FILE *f, BOOL print_lengths) +#elif defined COMPILE_PCRE32 +void +pcre32_printint(pcre *external_re, FILE *f, BOOL print_lengths) #endif { REAL_PCRE *re = (REAL_PCRE *)external_re; @@ -274,15 +330,15 @@ if (re->magic_number != MAGIC_NUMBER) } code = codestart = (pcre_uchar *)re + offset + count * size; -/* PCRE_UTF16 has the same value as PCRE_UTF8. */ +/* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */ utf = (options & PCRE_UTF8) != 0; for(;;) { pcre_uchar *ccode; const char *flag = " "; - int c; - int extra = 0; + pcre_uint32 c; + unsigned int extra = 0; if (print_lengths) fprintf(f, "%3d ", (int)(code - codestart)); @@ -369,10 +425,19 @@ for(;;) break; case OP_CREF: - case OP_NCREF: fprintf(f, "%3d %s", GET2(code,1), priv_OP_names[*code]); break; + case OP_DNCREF: + { + pcre_uchar *entry = (pcre_uchar *)re + offset + (GET2(code, 1) * size) + + IMM2_SIZE; + fprintf(f, " %s Cond ref <", flag); + print_puchar(f, entry); + fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE)); + } + break; + case OP_RREF: c = GET2(code, 1); if (c == RREF_ANY) @@ -381,12 +446,14 @@ for(;;) fprintf(f, " Cond recurse %d", c); break; - case OP_NRREF: - c = GET2(code, 1); - if (c == RREF_ANY) - fprintf(f, " Cond nrecurse any"); - else - fprintf(f, " Cond nrecurse %d", c); + case OP_DNRREF: + { + pcre_uchar *entry = (pcre_uchar *)re + offset + (GET2(code, 1) * size) + + IMM2_SIZE; + fprintf(f, " %s Cond recurse <", flag); + print_puchar(f, entry); + fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE)); + } break; case OP_DEF: @@ -425,12 +492,12 @@ for(;;) fprintf(f, " %s ", flag); if (*code >= OP_TYPESTAR) { - fprintf(f, "%s", priv_OP_names[code[1]]); if (code[1] == OP_PROP || code[1] == OP_NOTPROP) { - fprintf(f, " %s ", get_ucpname(code[2], code[3])); + print_prop(f, code + 1, "", " "); extra = 2; } + else fprintf(f, "%s", priv_OP_names[code[1]]); } else extra = print_char(f, code+1, utf); fprintf(f, "%s", priv_OP_names[*code]); @@ -459,13 +526,12 @@ for(;;) case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEPOSUPTO: - fprintf(f, " %s", priv_OP_names[code[1 + IMM2_SIZE]]); if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) { - fprintf(f, " %s ", get_ucpname(code[1 + IMM2_SIZE + 1], - code[1 + IMM2_SIZE + 2])); + print_prop(f, code + IMM2_SIZE + 1, " ", " "); extra = 2; } + else fprintf(f, " %s", priv_OP_names[code[1 + IMM2_SIZE]]); fprintf(f, "{"); if (*code != OP_TYPEEXACT) fprintf(f, "0,"); fprintf(f, "%d}", GET2(code,1)); @@ -543,6 +609,20 @@ for(;;) ccode = code + priv_OP_lengths[*code]; goto CLASS_REF_REPEAT; + case OP_DNREFI: + flag = "/i"; + /* Fall through */ + case OP_DNREF: + { + pcre_uchar *entry = (pcre_uchar *)re + offset + (GET2(code, 1) * size) + + IMM2_SIZE; + fprintf(f, " %s \\k<", flag); + print_puchar(f, entry); + fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE)); + } + ccode = code + priv_OP_lengths[*code]; + goto CLASS_REF_REPEAT; + case OP_CALLOUT: fprintf(f, " %s %d %d %d", priv_OP_names[*code], code[1], GET(code,2), GET(code, 2 + LINK_SIZE)); @@ -550,18 +630,19 @@ for(;;) case OP_PROP: case OP_NOTPROP: - fprintf(f, " %s %s", priv_OP_names[*code], get_ucpname(code[1], code[2])); + print_prop(f, code, " ", ""); break; - /* OP_XCLASS can only occur in UTF or PCRE16 modes. However, there's no - harm in having this code always here, and it makes it less messy without - all those #ifdefs. */ + /* OP_XCLASS cannot occur in 8-bit, non-UTF mode. However, there's no harm + in having this code always here, and it makes it less messy without all + those #ifdefs. */ case OP_CLASS: case OP_NCLASS: case OP_XCLASS: { - int i, min, max; + int i; + unsigned int min, max; BOOL printmap; pcre_uint8 *map; @@ -612,29 +693,54 @@ for(;;) if (*code == OP_XCLASS) { - int ch; + pcre_uchar ch; while ((ch = *ccode++) != XCL_END) { - if (ch == XCL_PROP) - { - int ptype = *ccode++; - int pvalue = *ccode++; - fprintf(f, "\\p{%s}", get_ucpname(ptype, pvalue)); - } - else if (ch == XCL_NOTPROP) - { - int ptype = *ccode++; - int pvalue = *ccode++; - fprintf(f, "\\P{%s}", get_ucpname(ptype, pvalue)); - } - else + BOOL not = FALSE; + const char *notch = ""; + + switch(ch) { + case XCL_NOTPROP: + not = TRUE; + notch = "^"; + /* Fall through */ + + case XCL_PROP: + { + unsigned int ptype = *ccode++; + unsigned int pvalue = *ccode++; + + switch(ptype) + { + case PT_PXGRAPH: + fprintf(f, "[:%sgraph:]", notch); + break; + + case PT_PXPRINT: + fprintf(f, "[:%sprint:]", notch); + break; + + case PT_PXPUNCT: + fprintf(f, "[:%spunct:]", notch); + break; + + default: + fprintf(f, "\\%c{%s}", (not? 'P':'p'), + get_ucpname(ptype, pvalue)); + break; + } + } + break; + + default: ccode += 1 + print_char(f, ccode, utf); if (ch == XCL_RANGE) { fprintf(f, "-"); ccode += 1 + print_char(f, ccode, utf); } + break; } } } @@ -654,17 +760,22 @@ for(;;) case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSPLUS: + case OP_CRPOSQUERY: fprintf(f, "%s", priv_OP_names[*ccode]); extra += priv_OP_lengths[*ccode]; break; case OP_CRRANGE: case OP_CRMINRANGE: + case OP_CRPOSRANGE: min = GET2(ccode,1); max = GET2(ccode,1 + IMM2_SIZE); - if (max == 0) fprintf(f, "{%d,}", min); - else fprintf(f, "{%d,%d}", min, max); + if (max == 0) fprintf(f, "{%u,}", min); + else fprintf(f, "{%u,%u}", min, max); if (*ccode == OP_CRMINRANGE) fprintf(f, "?"); + else if (*ccode == OP_CRPOSRANGE) fprintf(f, "+"); extra += priv_OP_lengths[*ccode]; break; diff --git a/src/3rd/pcre/pcrerefc.c b/src/3rd/pcre/pcrerefc.c index 8a0f0c8e19..868a35bcaa 100644 --- a/src/3rd/pcre/pcrerefc.c +++ b/src/3rd/pcre/pcrerefc.c @@ -68,12 +68,15 @@ Returns: the (possibly updated) count value (a non-negative number), or a negative error number */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_refcount(pcre *argument_re, int adjust) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_refcount(pcre16 *argument_re, int adjust) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN int PCRE_CALL_CONVENTION +pcre32_refcount(pcre32 *argument_re, int adjust) #endif { REAL_PCRE *re = (REAL_PCRE *)argument_re; diff --git a/src/3rd/pcre/pcrestud.c b/src/3rd/pcre/pcrestud.c index 3e196b90e3..81a88da1a3 100644 --- a/src/3rd/pcre/pcrestud.c +++ b/src/3rd/pcre/pcrestud.c @@ -66,8 +66,9 @@ string of that length that matches. In UTF8 mode, the result is in characters rather than bytes. Arguments: + re compiled pattern block code pointer to start of group (the bracket) - startcode pointer to start of the whole pattern + startcode pointer to start of the whole pattern's code options the compiling options int RECURSE depth @@ -78,8 +79,8 @@ Returns: the minimum length */ static int -find_minlength(const pcre_uchar *code, const pcre_uchar *startcode, int options, - int recurse_depth) +find_minlength(const REAL_PCRE *re, const pcre_uchar *code, + const pcre_uchar *startcode, int options, int recurse_depth) { int length = -1; /* PCRE_UTF16 has the same value as PCRE_UTF8. */ @@ -98,7 +99,7 @@ for (;;) { int d, min; pcre_uchar *cs, *ce; - register int op = *cc; + register pcre_uchar op = *cc; switch (op) { @@ -129,7 +130,7 @@ for (;;) case OP_SBRAPOS: case OP_ONCE: case OP_ONCE_NC: - d = find_minlength(cc, startcode, options, recurse_depth); + d = find_minlength(re, cc, startcode, options, recurse_depth); if (d < 0) return d; branchlength += d; do cc += GET(cc, 1); while (*cc == OP_ALT); @@ -175,9 +176,9 @@ for (;;) case OP_REVERSE: case OP_CREF: - case OP_NCREF: + case OP_DNCREF: case OP_RREF: - case OP_NRREF: + case OP_DNRREF: case OP_DEF: case OP_CALLOUT: case OP_SOD: @@ -323,20 +324,25 @@ for (;;) /* Check a class for variable quantification */ -#if defined SUPPORT_UTF || !defined COMPILE_PCRE8 - case OP_XCLASS: - cc += GET(cc, 1) - PRIV(OP_lengths)[OP_CLASS]; - /* Fall through */ -#endif - case OP_CLASS: case OP_NCLASS: +#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + case OP_XCLASS: + /* The original code caused an unsigned overflow in 64 bit systems, + so now we use a conditional statement. */ + if (op == OP_XCLASS) + cc += GET(cc, 1); + else + cc += PRIV(OP_lengths)[OP_CLASS]; +#else cc += PRIV(OP_lengths)[OP_CLASS]; +#endif switch (*cc) { case OP_CRPLUS: case OP_CRMINPLUS: + case OP_CRPOSPLUS: branchlength++; /* Fall through */ @@ -344,11 +350,14 @@ for (;;) case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSQUERY: cc++; break; case OP_CRRANGE: case OP_CRMINRANGE: + case OP_CRPOSRANGE: branchlength += GET2(cc,1); cc += 1 + 2 * IMM2_SIZE; break; @@ -371,7 +380,38 @@ for (;;) matches an empty string (by default it causes a matching failure), so in that case we must set the minimum length to zero. */ - case OP_REF: + case OP_DNREF: /* Duplicate named pattern back reference */ + case OP_DNREFI: + if ((options & PCRE_JAVASCRIPT_COMPAT) == 0) + { + int count = GET2(cc, 1+IMM2_SIZE); + pcre_uchar *slot = (pcre_uchar *)re + + re->name_table_offset + GET2(cc, 1) * re->name_entry_size; + d = INT_MAX; + while (count-- > 0) + { + ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(slot, 0)); + if (cs == NULL) return -2; + do ce += GET(ce, 1); while (*ce == OP_ALT); + if (cc > cs && cc < ce) + { + d = 0; + had_recurse = TRUE; + break; + } + else + { + int dd = find_minlength(re, cs, startcode, options, recurse_depth); + if (dd < d) d = dd; + } + slot += re->name_entry_size; + } + } + else d = 0; + cc += 1 + 2*IMM2_SIZE; + goto REPEAT_BACK_REFERENCE; + + case OP_REF: /* Single back reference */ case OP_REFI: if ((options & PCRE_JAVASCRIPT_COMPAT) == 0) { @@ -385,7 +425,7 @@ for (;;) } else { - d = find_minlength(cs, startcode, options, recurse_depth); + d = find_minlength(re, cs, startcode, options, recurse_depth); } } else d = 0; @@ -393,24 +433,29 @@ for (;;) /* Handle repeated back references */ + REPEAT_BACK_REFERENCE: switch (*cc) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSQUERY: min = 0; cc++; break; case OP_CRPLUS: case OP_CRMINPLUS: + case OP_CRPOSPLUS: min = 1; cc++; break; case OP_CRRANGE: case OP_CRMINRANGE: + case OP_CRPOSRANGE: min = GET2(cc, 1); cc += 1 + 2 * IMM2_SIZE; break; @@ -433,7 +478,8 @@ for (;;) had_recurse = TRUE; else { - branchlength += find_minlength(cs, startcode, options, recurse_depth + 1); + branchlength += find_minlength(re, cs, startcode, options, + recurse_depth + 1); } cc += 1 + LINK_SIZE; break; @@ -538,7 +584,7 @@ Arguments: p points to the character caseless the caseless flag cd the block with char table pointers - utf TRUE for UTF-8 / UTF-16 mode + utf TRUE for UTF-8 / UTF-16 / UTF-32 mode Returns: pointer after the character */ @@ -547,7 +593,7 @@ static const pcre_uchar * set_table_bit(pcre_uint8 *start_bits, const pcre_uchar *p, BOOL caseless, compile_data *cd, BOOL utf) { -unsigned int c = *p; +pcre_uint32 c = *p; #ifdef COMPILE_PCRE8 SET_BIT(c); @@ -564,18 +610,20 @@ if (utf && c > 127) (void)PRIV(ord2utf)(c, buff); SET_BIT(buff[0]); } -#endif +#endif /* Not SUPPORT_UCP */ return p; } -#endif +#else /* Not SUPPORT_UTF */ +(void)(utf); /* Stops warning for unused parameter */ +#endif /* SUPPORT_UTF */ /* Not UTF-8 mode, or character is less than 127. */ if (caseless && (cd->ctypes[c] & ctype_letter) != 0) SET_BIT(cd->fcc[c]); return p + 1; -#endif +#endif /* COMPILE_PCRE8 */ -#ifdef COMPILE_PCRE16 +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 if (c > 0xff) { c = 0xff; @@ -595,10 +643,12 @@ if (utf && c > 127) c = 0xff; SET_BIT(c); } -#endif +#endif /* SUPPORT_UCP */ return p; } -#endif +#else /* Not SUPPORT_UTF */ +(void)(utf); /* Stops warning for unused parameter */ +#endif /* SUPPORT_UTF */ if (caseless && (cd->ctypes[c] & ctype_letter) != 0) SET_BIT(cd->fcc[c]); return p + 1; @@ -628,10 +678,10 @@ Returns: nothing */ static void -set_type_bits(pcre_uint8 *start_bits, int cbit_type, int table_limit, +set_type_bits(pcre_uint8 *start_bits, int cbit_type, unsigned int table_limit, compile_data *cd) { -register int c; +register pcre_uint32 c; for (c = 0; c < table_limit; c++) start_bits[c] |= cd->cbits[c+cbit_type]; #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (table_limit == 32) return; @@ -670,10 +720,10 @@ Returns: nothing */ static void -set_nottype_bits(pcre_uint8 *start_bits, int cbit_type, int table_limit, +set_nottype_bits(pcre_uint8 *start_bits, int cbit_type, unsigned int table_limit, compile_data *cd) { -register int c; +register pcre_uint32 c; for (c = 0; c < table_limit; c++) start_bits[c] |= ~cd->cbits[c+cbit_type]; #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (table_limit != 32) for (c = 24; c < 32; c++) start_bits[c] = 0xff; @@ -697,7 +747,7 @@ function fails unless the result is SSB_DONE. Arguments: code points to an expression start_bits points to a 32-byte table, initialized to 0 - utf TRUE if in UTF-8 / UTF-16 mode + utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode cd the block with char table pointers Returns: SSB_FAIL => Failed to find any starting bytes @@ -710,7 +760,7 @@ static int set_start_bits(const pcre_uchar *code, pcre_uint8 *start_bits, BOOL utf, compile_data *cd) { -register int c; +register pcre_uint32 c; int yield = SSB_DONE; #if defined SUPPORT_UTF && defined COMPILE_PCRE8 int table_limit = utf? 16:32; @@ -770,6 +820,10 @@ do case OP_COND: case OP_CREF: case OP_DEF: + case OP_DNCREF: + case OP_DNREF: + case OP_DNREFI: + case OP_DNRREF: case OP_DOLL: case OP_DOLLM: case OP_END: @@ -778,7 +832,6 @@ do case OP_EXTUNI: case OP_FAIL: case OP_MARK: - case OP_NCREF: case OP_NOT: case OP_NOTEXACT: case OP_NOTEXACTI: @@ -810,7 +863,6 @@ do case OP_NOTUPTOI: case OP_NOT_HSPACE: case OP_NOT_VSPACE: - case OP_NRREF: case OP_PROP: case OP_PRUNE: case OP_PRUNE_ARG: @@ -986,8 +1038,8 @@ do identical. */ case OP_HSPACE: - SET_BIT(0x09); - SET_BIT(0x20); + SET_BIT(CHAR_HT); + SET_BIT(CHAR_SPACE); #ifdef SUPPORT_UTF if (utf) { @@ -996,46 +1048,46 @@ do SET_BIT(0xE1); /* For U+1680, U+180E */ SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */ SET_BIT(0xE3); /* For U+3000 */ -#endif -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xA0); SET_BIT(0xFF); /* For characters > 255 */ -#endif +#endif /* COMPILE_PCRE[8|16|32] */ } else #endif /* SUPPORT_UTF */ { +#ifndef EBCDIC SET_BIT(0xA0); -#ifdef COMPILE_PCRE16 +#endif /* Not EBCDIC */ +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xFF); /* For characters > 255 */ -#endif +#endif /* COMPILE_PCRE[16|32] */ } try_next = FALSE; break; case OP_ANYNL: case OP_VSPACE: - SET_BIT(0x0A); - SET_BIT(0x0B); - SET_BIT(0x0C); - SET_BIT(0x0D); + SET_BIT(CHAR_LF); + SET_BIT(CHAR_VT); + SET_BIT(CHAR_FF); + SET_BIT(CHAR_CR); #ifdef SUPPORT_UTF if (utf) { #ifdef COMPILE_PCRE8 SET_BIT(0xC2); /* For U+0085 */ SET_BIT(0xE2); /* For U+2028, U+2029 */ -#endif -#ifdef COMPILE_PCRE16 - SET_BIT(0x85); +#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + SET_BIT(CHAR_NEL); SET_BIT(0xFF); /* For characters > 255 */ -#endif +#endif /* COMPILE_PCRE[8|16|32] */ } else #endif /* SUPPORT_UTF */ { - SET_BIT(0x85); -#ifdef COMPILE_PCRE16 + SET_BIT(CHAR_NEL); +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xFF); /* For characters > 255 */ #endif } @@ -1058,7 +1110,8 @@ do break; /* The cbit_space table has vertical tab as whitespace; we have to - ensure it is set as not whitespace. */ + ensure it is set as not whitespace. Luckily, the code value is the same + (0x0b) in ASCII and EBCDIC, so we can just adjust the appropriate bit. */ case OP_NOT_WHITESPACE: set_nottype_bits(start_bits, cbit_space, table_limit, cd); @@ -1066,8 +1119,9 @@ do try_next = FALSE; break; - /* The cbit_space table has vertical tab as whitespace; we have to - not set it from the table. */ + /* The cbit_space table has vertical tab as whitespace; we have to not + set it from the table. Luckily, the code value is the same (0x0b) in + ASCII and EBCDIC, so we can just adjust the appropriate bit. */ case OP_WHITESPACE: c = start_bits[1]; /* Save in case it was already set */ @@ -1121,8 +1175,8 @@ do return SSB_FAIL; case OP_HSPACE: - SET_BIT(0x09); - SET_BIT(0x20); + SET_BIT(CHAR_HT); + SET_BIT(CHAR_SPACE); #ifdef SUPPORT_UTF if (utf) { @@ -1131,38 +1185,38 @@ do SET_BIT(0xE1); /* For U+1680, U+180E */ SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */ SET_BIT(0xE3); /* For U+3000 */ -#endif -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xA0); SET_BIT(0xFF); /* For characters > 255 */ -#endif +#endif /* COMPILE_PCRE[8|16|32] */ } else #endif /* SUPPORT_UTF */ +#ifndef EBCDIC SET_BIT(0xA0); +#endif /* Not EBCDIC */ break; case OP_ANYNL: case OP_VSPACE: - SET_BIT(0x0A); - SET_BIT(0x0B); - SET_BIT(0x0C); - SET_BIT(0x0D); + SET_BIT(CHAR_LF); + SET_BIT(CHAR_VT); + SET_BIT(CHAR_FF); + SET_BIT(CHAR_CR); #ifdef SUPPORT_UTF if (utf) { #ifdef COMPILE_PCRE8 SET_BIT(0xC2); /* For U+0085 */ SET_BIT(0xE2); /* For U+2028, U+2029 */ -#endif -#ifdef COMPILE_PCRE16 - SET_BIT(0x85); +#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 + SET_BIT(CHAR_NEL); SET_BIT(0xFF); /* For characters > 255 */ -#endif +#endif /* COMPILE_PCRE16 */ } else #endif /* SUPPORT_UTF */ - SET_BIT(0x85); + SET_BIT(CHAR_NEL); break; case OP_NOT_DIGIT: @@ -1173,21 +1227,16 @@ do set_type_bits(start_bits, cbit_digit, table_limit, cd); break; - /* The cbit_space table has vertical tab as whitespace; we have to - ensure it gets set as not whitespace. */ + /* The cbit_space table has vertical tab as whitespace; we no longer + have to play fancy tricks because Perl added VT to its whitespace at + release 5.18. PCRE added it at release 8.34. */ case OP_NOT_WHITESPACE: set_nottype_bits(start_bits, cbit_space, table_limit, cd); - start_bits[1] |= 0x08; break; - /* The cbit_space table has vertical tab as whitespace; we have to - avoid setting it. */ - case OP_WHITESPACE: - c = start_bits[1]; /* Save in case it was already set */ set_type_bits(start_bits, cbit_space, table_limit, cd); - start_bits[1] = (start_bits[1] & ~0x08) | c; break; case OP_NOT_WORDCHAR: @@ -1216,7 +1265,7 @@ do memset(start_bits+25, 0xff, 7); /* Bits for 0xc9 - 0xff */ } #endif -#ifdef COMPILE_PCRE16 +#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xFF); /* For characters > 255 */ #endif /* Fall through */ @@ -1264,11 +1313,14 @@ do case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: + case OP_CRPOSSTAR: + case OP_CRPOSQUERY: tcode++; break; case OP_CRRANGE: case OP_CRMINRANGE: + case OP_CRPOSRANGE: if (GET2(tcode, 1) == 0) tcode += 1 + 2 * IMM2_SIZE; else try_next = FALSE; break; @@ -1312,12 +1364,15 @@ Returns: pointer to a pcre[16]_extra block, with study_data filled in and NULL on error or if no optimization possible */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN pcre_extra * PCRE_CALL_CONVENTION pcre_study(const pcre *external_re, int options, const char **errorptr) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN pcre16_extra * PCRE_CALL_CONVENTION pcre16_study(const pcre16 *external_re, int options, const char **errorptr) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN pcre32_extra * PCRE_CALL_CONVENTION +pcre32_study(const pcre32 *external_re, int options, const char **errorptr) #endif { int min; @@ -1330,6 +1385,7 @@ pcre_uchar *code; compile_data compile_block; const REAL_PCRE *re = (const REAL_PCRE *)external_re; + *errorptr = NULL; if (re == NULL || re->magic_number != MAGIC_NUMBER) @@ -1340,10 +1396,12 @@ if (re == NULL || re->magic_number != MAGIC_NUMBER) if ((re->flags & PCRE_MODE) == 0) { -#ifdef COMPILE_PCRE8 - *errorptr = "argument is compiled in 16 bit mode"; -#else - *errorptr = "argument is compiled in 8 bit mode"; +#if defined COMPILE_PCRE8 + *errorptr = "argument not compiled in 8 bit mode"; +#elif defined COMPILE_PCRE16 + *errorptr = "argument not compiled in 16 bit mode"; +#elif defined COMPILE_PCRE32 + *errorptr = "argument not compiled in 32 bit mode"; #endif return NULL; } @@ -1370,14 +1428,18 @@ if ((re->options & PCRE_ANCHORED) == 0 && tables = re->tables; -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 if (tables == NULL) (void)pcre_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES, (void *)(&tables)); -#else +#elif defined COMPILE_PCRE16 if (tables == NULL) (void)pcre16_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES, (void *)(&tables)); +#elif defined COMPILE_PCRE32 + if (tables == NULL) + (void)pcre32_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES, + (void *)(&tables)); #endif compile_block.lcc = tables + lcc_offset; @@ -1400,7 +1462,7 @@ if ((re->options & PCRE_ANCHORED) == 0 && /* Find the minimum length of subject string. */ -switch(min = find_minlength(code, code, re->options, 0)) +switch(min = find_minlength(re, code, code, re->options, 0)) { case -2: *errorptr = "internal error: missing capturing bracket"; return NULL; case -3: *errorptr = "internal error: opcode not recognized"; return NULL; @@ -1408,20 +1470,20 @@ switch(min = find_minlength(code, code, re->options, 0)) } /* If a set of starting bytes has been identified, or if the minimum length is -greater than zero, or if JIT optimization has been requested, get a -pcre[16]_extra block and a pcre_study_data block. The study data is put in the -latter, which is pointed to by the former, which may also get additional data -set later by the calling program. At the moment, the size of pcre_study_data -is fixed. We nevertheless save it in a field for returning via the -pcre_fullinfo() function so that if it becomes variable in the future, -we don't have to change that code. */ +greater than zero, or if JIT optimization has been requested, or if +PCRE_STUDY_EXTRA_NEEDED is set, get a pcre[16]_extra block and a +pcre_study_data block. The study data is put in the latter, which is pointed to +by the former, which may also get additional data set later by the calling +program. At the moment, the size of pcre_study_data is fixed. We nevertheless +save it in a field for returning via the pcre_fullinfo() function so that if it +becomes variable in the future, we don't have to change that code. */ -if (bits_set || min > 0 +if (bits_set || min > 0 || (options & ( #ifdef SUPPORT_JIT - || (options & (PCRE_STUDY_JIT_COMPILE | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE - | PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE)) != 0 + PCRE_STUDY_JIT_COMPILE | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE | + PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE | #endif - ) + PCRE_STUDY_EXTRA_NEEDED)) != 0) { extra = (PUBL(extra) *)(PUBL(malloc)) (sizeof(PUBL(extra)) + sizeof(pcre_study_data)); @@ -1475,7 +1537,8 @@ if (bits_set || min > 0 /* If JIT support was compiled and requested, attempt the JIT compilation. If no starting bytes were found, and the minimum length is zero, and JIT - compilation fails, abandon the extra block and return NULL. */ + compilation fails, abandon the extra block and return NULL, unless + PCRE_STUDY_EXTRA_NEEDED is set. */ #ifdef SUPPORT_JIT extra->executable_jit = NULL; @@ -1486,13 +1549,15 @@ if (bits_set || min > 0 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) + if (study->flags == 0 && (extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) == 0 && + (options & PCRE_STUDY_EXTRA_NEEDED) == 0) { -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 pcre_free_study(extra); -#endif -#ifdef COMPILE_PCRE16 +#elif defined COMPILE_PCRE16 pcre16_free_study(extra); +#elif defined COMPILE_PCRE32 + pcre32_free_study(extra); #endif extra = NULL; } @@ -1513,12 +1578,15 @@ Argument: a pointer to the pcre[16]_extra block Returns: nothing */ -#ifdef COMPILE_PCRE8 +#if defined COMPILE_PCRE8 PCRE_EXP_DEFN void pcre_free_study(pcre_extra *extra) -#else +#elif defined COMPILE_PCRE16 PCRE_EXP_DEFN void pcre16_free_study(pcre16_extra *extra) +#elif defined COMPILE_PCRE32 +PCRE_EXP_DEFN void +pcre32_free_study(pcre32_extra *extra) #endif { if (extra == NULL) diff --git a/src/3rd/pcre/pcretabs.c b/src/3rd/pcre/pcretabs.c index 212c65cf13..cdb9712615 100644 --- a/src/3rd/pcre/pcretabs.c +++ b/src/3rd/pcre/pcretabs.c @@ -58,6 +58,12 @@ the definition is next to the definition of the opcodes in pcre_internal.h. */ const pcre_uint8 PRIV(OP_lengths)[] = { OP_LENGTHS }; +/* Tables of horizontal and vertical whitespace characters, suitable for +adding to classes. */ + +const pcre_uint32 PRIV(hspace_list)[] = { HSPACE_LIST }; +const pcre_uint32 PRIV(vspace_list)[] = { VSPACE_LIST }; + /************************************************* @@ -68,9 +74,9 @@ const pcre_uint8 PRIV(OP_lengths)[] = { OP_LENGTHS }; character. */ #if (defined SUPPORT_UTF && defined COMPILE_PCRE8) \ - || (defined PCRE_INCLUDED && defined SUPPORT_PCRE16) + || (defined PCRE_INCLUDED && (defined SUPPORT_PCRE16 || defined SUPPORT_PCRE32)) -/* These tables are also required by pcretest in 16 bit mode. */ +/* These tables are also required by pcretest in 16- or 32-bit mode. */ const int PRIV(utf8_table1)[] = { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; @@ -92,13 +98,13 @@ const pcre_uint8 PRIV(utf8_table4)[] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; -#endif /* (SUPPORT_UTF && COMPILE_PCRE8) || (PCRE_INCLUDED && SUPPORT_PCRE16)*/ +#endif /* (SUPPORT_UTF && COMPILE_PCRE8) || (PCRE_INCLUDED && SUPPORT_PCRE[16|32])*/ #ifdef SUPPORT_UTF /* Table to translate from particular type value to the general value. */ -const int PRIV(ucp_gentype)[] = { +const pcre_uint32 PRIV(ucp_gentype)[] = { ucp_C, ucp_C, ucp_C, ucp_C, ucp_C, /* Cc, Cf, Cn, Co, Cs */ ucp_L, ucp_L, ucp_L, ucp_L, ucp_L, /* Ll, Lu, Lm, Lo, Lt */ ucp_M, ucp_M, ucp_M, /* Mc, Me, Mn */ @@ -109,6 +115,66 @@ const int PRIV(ucp_gentype)[] = { ucp_Z, ucp_Z, ucp_Z /* Zl, Zp, Zs */ }; +/* This table encodes the rules for finding the end of an extended grapheme +cluster. Every code point has a grapheme break property which is one of the +ucp_gbXX values defined in ucp.h. The 2-dimensional table is indexed by the +properties of two adjacent code points. The left property selects a word from +the table, and the right property selects a bit from that word like this: + + ucp_gbtable[left-property] & (1 << right-property) + +The value is non-zero if a grapheme break is NOT permitted between the relevant +two code points. The breaking rules are as follows: + +1. Break at the start and end of text (pretty obviously). + +2. Do not break between a CR and LF; otherwise, break before and after + controls. + +3. Do not break Hangul syllable sequences, the rules for which are: + + L may be followed by L, V, LV or LVT + LV or V may be followed by V or T + LVT or T may be followed by T + +4. Do not break before extending characters. + +The next two rules are only for extended grapheme clusters (but that's what we +are implementing). + +5. Do not break before SpacingMarks. + +6. Do not break after Prepend characters. + +7. Otherwise, break everywhere. +*/ + +const pcre_uint32 PRIV(ucp_gbtable[]) = { + (1< 0; p++) { - register int ab, c, d; + register pcre_uchar ab, c, d; c = *p; if (c < 128) continue; /* ASCII character */ @@ -288,9 +289,10 @@ for (p = string; length-- > 0; p++) } } -#else /* SUPPORT_UTF */ +#else /* Not SUPPORT_UTF */ (void)(string); /* Keep picky compilers happy */ (void)(length); +(void)(erroroffset); #endif return PCRE_UTF8_ERR0; /* This indicates success */ diff --git a/src/3rd/pcre/pcrexcls.c b/src/3rd/pcre/pcrexcls.c index dcd06ae3c6..80051f8f10 100644 --- a/src/3rd/pcre/pcrexcls.c +++ b/src/3rd/pcre/pcrexcls.c @@ -6,7 +6,7 @@ and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel - Copyright (c) 1997-2012 University of Cambridge + Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without @@ -64,9 +64,9 @@ Returns: TRUE if character matches, else FALSE */ BOOL -PRIV(xclass)(int c, const pcre_uchar *data, BOOL utf) +PRIV(xclass)(pcre_uint32 c, const pcre_uchar *data, BOOL utf) { -int t; +pcre_uchar t; BOOL negated = (*data & XCL_NOT) != 0; (void)utf; @@ -94,7 +94,7 @@ if ((*data++ & XCL_MAP) != 0) data += 32 / sizeof(pcre_uchar); while ((t = *data++) != XCL_END) { - int x, y; + pcre_uint32 x, y; if (t == XCL_SINGLE) { #ifdef SUPPORT_UTF @@ -128,55 +128,120 @@ while ((t = *data++) != XCL_END) else /* XCL_PROP & XCL_NOTPROP */ { const ucd_record *prop = GET_UCD(c); + BOOL isprop = t == XCL_PROP; switch(*data) { case PT_ANY: - if (t == XCL_PROP) return !negated; + if (isprop) return !negated; break; case PT_LAMP: if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || - prop->chartype == ucp_Lt) == (t == XCL_PROP)) return !negated; + prop->chartype == ucp_Lt) == isprop) return !negated; break; case PT_GC: - if ((data[1] == PRIV(ucp_gentype)[prop->chartype]) == (t == XCL_PROP)) + if ((data[1] == PRIV(ucp_gentype)[prop->chartype]) == isprop) return !negated; break; case PT_PC: - if ((data[1] == prop->chartype) == (t == XCL_PROP)) return !negated; + if ((data[1] == prop->chartype) == isprop) return !negated; break; case PT_SC: - if ((data[1] == prop->script) == (t == XCL_PROP)) return !negated; + if ((data[1] == prop->script) == isprop) return !negated; break; case PT_ALNUM: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || - PRIV(ucp_gentype)[prop->chartype] == ucp_N) == (t == XCL_PROP)) + PRIV(ucp_gentype)[prop->chartype] == ucp_N) == isprop) return !negated; break; + /* Perl space used to exclude VT, but from Perl 5.18 it is included, + which means that Perl space and POSIX space are now identical. PCRE + was changed at release 8.34. */ + case PT_SPACE: /* Perl space */ - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR) - == (t == XCL_PROP)) - return !negated; - break; - case PT_PXSPACE: /* POSIX space */ - if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z || - c == CHAR_HT || c == CHAR_NL || c == CHAR_VT || - c == CHAR_FF || c == CHAR_CR) == (t == XCL_PROP)) - return !negated; + switch(c) + { + HSPACE_CASES: + VSPACE_CASES: + if (isprop) return !negated; + break; + + default: + if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == isprop) + return !negated; + break; + } break; case PT_WORD: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE) - == (t == XCL_PROP)) + == isprop) + return !negated; + break; + + case PT_UCNC: + if (c < 0xa0) + { + if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || + c == CHAR_GRAVE_ACCENT) == isprop) + return !negated; + } + else + { + if ((c < 0xd800 || c > 0xdfff) == isprop) + return !negated; + } + break; + + /* The following three properties can occur only in an XCLASS, as there + is no \p or \P coding for them. */ + + /* Graphic character. Implement this as not Z (space or separator) and + not C (other), except for Cf (format) with a few exceptions. This seems + to be what Perl does. The exceptional characters are: + + U+061C Arabic Letter Mark + U+180E Mongolian Vowel Separator + U+2066 - U+2069 Various "isolate"s + */ + + case PT_PXGRAPH: + if ((PRIV(ucp_gentype)[prop->chartype] != ucp_Z && + (PRIV(ucp_gentype)[prop->chartype] != ucp_C || + (prop->chartype == ucp_Cf && + c != 0x061c && c != 0x180e && (c < 0x2066 || c > 0x2069)) + )) == isprop) + return !negated; + break; + + /* Printable character: same as graphic, with the addition of Zs, i.e. + not Zl and not Zp, and U+180E. */ + + case PT_PXPRINT: + if ((prop->chartype != ucp_Zl && + prop->chartype != ucp_Zp && + (PRIV(ucp_gentype)[prop->chartype] != ucp_C || + (prop->chartype == ucp_Cf && + c != 0x061c && (c < 0x2066 || c > 0x2069)) + )) == isprop) + return !negated; + break; + + /* Punctuation: all Unicode punctuation, plus ASCII characters that + Unicode treats as symbols rather than punctuation, for Perl + compatibility (these are $+<=>^`|~). */ + + case PT_PXPUNCT: + if ((PRIV(ucp_gentype)[prop->chartype] == ucp_P || + (c < 256 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop) return !negated; break; diff --git a/src/3rd/pcre/sjarmth2.c b/src/3rd/pcre/sjarmth2.c index 465c30d6ea..74ec83177d 100644 --- a/src/3rd/pcre/sjarmth2.c +++ b/src/3rd/pcre/sjarmth2.c @@ -24,23 +24,26 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() +SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void) { return "ARM-Thumb2" SLJIT_CPUINFO; } +/* Length of an instruction word. */ +typedef sljit_ui sljit_ins; + /* Last register + 1. */ #define TMP_REG1 (SLJIT_NO_REGISTERS + 1) #define TMP_REG2 (SLJIT_NO_REGISTERS + 2) #define TMP_REG3 (SLJIT_NO_REGISTERS + 3) #define TMP_PC (SLJIT_NO_REGISTERS + 4) -#define TMP_FREG1 (SLJIT_FLOAT_REG4 + 1) -#define TMP_FREG2 (SLJIT_FLOAT_REG4 + 2) +#define TMP_FREG1 (0) +#define TMP_FREG2 (SLJIT_FLOAT_REG6 + 1) /* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { - 0, 0, 1, 2, 12, 5, 6, 7, 8, 10, 11, 13, 3, 4, 14, 15 + 0, 0, 1, 2, 12, 5, 6, 7, 8, 10, 11, 13, 3, 4, 14, 15 }; #define COPY_BITS(src, from, to, bits) \ @@ -75,8 +78,6 @@ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { #define IMM12(imm) \ (COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff)) -typedef sljit_ui sljit_ins; - /* --------------------------------------------------------------------- */ /* Instrucion forms */ /* --------------------------------------------------------------------- */ @@ -165,18 +166,18 @@ typedef sljit_ui sljit_ins; #define UXTB_W 0xfa5ff080 #define UXTH 0xb280 #define UXTH_W 0xfa1ff080 -#define VABS_F64 0xeeb00bc0 -#define VADD_F64 0xee300b00 -#define VCMP_F64 0xeeb40b40 -#define VDIV_F64 0xee800b00 -#define VMOV_F64 0xeeb00b40 +#define VABS_F32 0xeeb00ac0 +#define VADD_F32 0xee300a00 +#define VCMP_F32 0xeeb40a40 +#define VDIV_F32 0xee800a00 +#define VMOV_F32 0xeeb00a40 #define VMRS 0xeef1fa10 -#define VMUL_F64 0xee200b00 -#define VNEG_F64 0xeeb10b40 -#define VSTR 0xed000b00 -#define VSUB_F64 0xee300b40 +#define VMUL_F32 0xee200a00 +#define VNEG_F32 0xeeb10a40 +#define VSTR_F32 0xed000a00 +#define VSUB_F32 0xee300a40 -static int push_inst16(struct sljit_compiler *compiler, sljit_ins inst) +static sljit_si push_inst16(struct sljit_compiler *compiler, sljit_ins inst) { sljit_uh *ptr; SLJIT_ASSERT(!(inst & 0xffff0000)); @@ -188,7 +189,7 @@ static int push_inst16(struct sljit_compiler *compiler, sljit_ins inst) return SLJIT_SUCCESS; } -static int push_inst32(struct sljit_compiler *compiler, sljit_ins inst) +static sljit_si push_inst32(struct sljit_compiler *compiler, sljit_ins inst) { sljit_uh *ptr = (sljit_uh*)ensure_buf(compiler, sizeof(sljit_ins)); FAIL_IF(!ptr); @@ -198,7 +199,7 @@ static int push_inst32(struct sljit_compiler *compiler, sljit_ins inst) return SLJIT_SUCCESS; } -static SLJIT_INLINE int emit_imm32_const(struct sljit_compiler *compiler, int dst, sljit_uw imm) +static SLJIT_INLINE sljit_si emit_imm32_const(struct sljit_compiler *compiler, sljit_si dst, sljit_uw imm) { FAIL_IF(push_inst32(compiler, MOVW | RD4(dst) | COPY_BITS(imm, 12, 16, 4) | COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff))); @@ -208,7 +209,7 @@ static SLJIT_INLINE int emit_imm32_const(struct sljit_compiler *compiler, int ds static SLJIT_INLINE void modify_imm32_const(sljit_uh* inst, sljit_uw new_imm) { - int dst = inst[1] & 0x0f00; + sljit_si dst = inst[1] & 0x0f00; SLJIT_ASSERT(((inst[0] & 0xfbf0) == (MOVW >> 16)) && ((inst[2] & 0xfbf0) == (MOVT >> 16)) && dst == (inst[3] & 0x0f00)); inst[0] = (MOVW >> 16) | COPY_BITS(new_imm, 12, 0, 4) | COPY_BITS(new_imm, 11, 10, 1); inst[1] = dst | COPY_BITS(new_imm, 8, 12, 3) | (new_imm & 0xff); @@ -216,9 +217,9 @@ static SLJIT_INLINE void modify_imm32_const(sljit_uh* inst, sljit_uw new_imm) inst[3] = dst | COPY_BITS(new_imm, 8 + 16, 12, 3) | ((new_imm & 0xff0000) >> 16); } -static SLJIT_INLINE int detect_jump_type(struct sljit_jump *jump, sljit_uh *code_ptr, sljit_uh *code) +static SLJIT_INLINE sljit_si detect_jump_type(struct sljit_jump *jump, sljit_uh *code_ptr, sljit_uh *code) { - sljit_w diff; + sljit_sw diff; if (jump->flags & SLJIT_REWRITABLE_JUMP) return 0; @@ -227,14 +228,14 @@ static SLJIT_INLINE int detect_jump_type(struct sljit_jump *jump, sljit_uh *code /* Branch to ARM code is not optimized yet. */ if (!(jump->u.target & 0x1)) return 0; - diff = ((sljit_w)jump->u.target - (sljit_w)(code_ptr + 2)) >> 1; + diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2)) >> 1; } else { SLJIT_ASSERT(jump->flags & JUMP_LABEL); - diff = ((sljit_w)(code + jump->u.label->size) - (sljit_w)(code_ptr + 2)) >> 1; + diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2)) >> 1; } - if (jump->flags & IS_CONDITIONAL) { + if (jump->flags & IS_COND) { SLJIT_ASSERT(!(jump->flags & IS_BL)); if (diff <= 127 && diff >= -128) { jump->flags |= B_TYPE1; @@ -271,7 +272,7 @@ static SLJIT_INLINE int detect_jump_type(struct sljit_jump *jump, sljit_uh *code return 0; } -static SLJIT_INLINE void inline_set_jump_addr(sljit_uw addr, sljit_uw new_addr, int flush) +static SLJIT_INLINE void inline_set_jump_addr(sljit_uw addr, sljit_uw new_addr, sljit_si flush) { sljit_uh* inst = (sljit_uh*)addr; modify_imm32_const(inst, new_addr); @@ -282,10 +283,10 @@ static SLJIT_INLINE void inline_set_jump_addr(sljit_uw addr, sljit_uw new_addr, static SLJIT_INLINE void set_jump_instruction(struct sljit_jump *jump) { - int type = (jump->flags >> 4) & 0xf; - sljit_w diff; + sljit_si type = (jump->flags >> 4) & 0xf; + sljit_sw diff; sljit_uh *jump_inst; - int s, j1, j2; + sljit_si s, j1, j2; if (SLJIT_UNLIKELY(type == 0)) { inline_set_jump_addr(jump->addr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0); @@ -294,33 +295,33 @@ static SLJIT_INLINE void set_jump_instruction(struct sljit_jump *jump) if (jump->flags & JUMP_ADDR) { SLJIT_ASSERT(jump->u.target & 0x1); - diff = ((sljit_w)jump->u.target - (sljit_w)(jump->addr + 4)) >> 1; + diff = ((sljit_sw)jump->u.target - (sljit_sw)(jump->addr + 4)) >> 1; } else - diff = ((sljit_w)(jump->u.label->addr) - (sljit_w)(jump->addr + 4)) >> 1; + diff = ((sljit_sw)(jump->u.label->addr) - (sljit_sw)(jump->addr + 4)) >> 1; jump_inst = (sljit_uh*)jump->addr; switch (type) { case 1: /* Encoding T1 of 'B' instruction */ - SLJIT_ASSERT(diff <= 127 && diff >= -128 && (jump->flags & IS_CONDITIONAL)); + SLJIT_ASSERT(diff <= 127 && diff >= -128 && (jump->flags & IS_COND)); jump_inst[0] = 0xd000 | (jump->flags & 0xf00) | (diff & 0xff); return; case 2: /* Encoding T3 of 'B' instruction */ - SLJIT_ASSERT(diff <= 524287 && diff >= -524288 && (jump->flags & IS_CONDITIONAL)); + SLJIT_ASSERT(diff <= 524287 && diff >= -524288 && (jump->flags & IS_COND)); jump_inst[0] = 0xf000 | COPY_BITS(jump->flags, 8, 6, 4) | COPY_BITS(diff, 11, 0, 6) | COPY_BITS(diff, 19, 10, 1); jump_inst[1] = 0x8000 | COPY_BITS(diff, 17, 13, 1) | COPY_BITS(diff, 18, 11, 1) | (diff & 0x7ff); return; case 3: - SLJIT_ASSERT(jump->flags & IS_CONDITIONAL); + SLJIT_ASSERT(jump->flags & IS_COND); *jump_inst++ = IT | ((jump->flags >> 4) & 0xf0) | 0x8; diff--; type = 5; break; case 4: /* Encoding T2 of 'B' instruction */ - SLJIT_ASSERT(diff <= 1023 && diff >= -1024 && !(jump->flags & IS_CONDITIONAL)); + SLJIT_ASSERT(diff <= 1023 && diff >= -1024 && !(jump->flags & IS_COND)); jump_inst[0] = 0xe000 | (diff & 0x7ff); return; } @@ -385,7 +386,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil label = label->next; } if (jump && jump->addr == half_count) { - jump->addr = (sljit_uw)code_ptr - ((jump->flags & IS_CONDITIONAL) ? 10 : 8); + jump->addr = (sljit_uw)code_ptr - ((jump->flags & IS_COND) ? 10 : 8); code_ptr -= detect_jump_type(jump, code_ptr, code); jump = jump->next; } @@ -409,7 +410,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(code_ptr - code <= (int)compiler->size); + SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); jump = compiler->jumps; while (jump) { @@ -417,9 +418,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil jump = jump->next; } - SLJIT_CACHE_FLUSH(code, code_ptr); compiler->error = SLJIT_ERR_COMPILED; - compiler->executable_size = compiler->size * sizeof(sljit_uh); + compiler->executable_size = (code_ptr - code) * sizeof(sljit_uh); + SLJIT_CACHE_FLUSH(code, code_ptr); /* Set thumb mode flag. */ return (void*)((sljit_uw)code | 0x1); } @@ -428,7 +429,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil static sljit_uw get_imm(sljit_uw imm) { /* Thumb immediate form. */ - int counter; + sljit_si counter; if (imm <= 0xff) return imm; @@ -474,7 +475,7 @@ static sljit_uw get_imm(sljit_uw imm) return ((imm >> 24) & 0x7f) | COPY_BITS(counter, 4, 26, 1) | COPY_BITS(counter, 1, 12, 3) | COPY_BITS(counter, 0, 7, 1); } -static int load_immediate(struct sljit_compiler *compiler, int dst, sljit_uw imm) +static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst, sljit_uw imm) { sljit_uw tmp; @@ -509,12 +510,12 @@ static int load_immediate(struct sljit_compiler *compiler, int dst, sljit_uw imm #define SLOW_SRC1 0x0800000 #define SLOW_SRC2 0x1000000 -static int emit_op_imm(struct sljit_compiler *compiler, int flags, int dst, sljit_uw arg1, sljit_uw arg2) +static sljit_si emit_op_imm(struct sljit_compiler *compiler, sljit_si flags, sljit_si dst, sljit_uw arg1, sljit_uw arg2) { /* dst must be register, TMP_REG1 arg1 must be register, TMP_REG1, imm arg2 must be register, TMP_REG2, imm */ - int reg; + sljit_si reg; sljit_uw imm, negated_imm; if (SLJIT_UNLIKELY((flags & (ARG1_IMM | ARG2_IMM)) == (ARG1_IMM | ARG2_IMM))) { @@ -542,7 +543,7 @@ static int emit_op_imm(struct sljit_compiler *compiler, int flags, int dst, slji /* No form with immediate operand. */ break; case SLJIT_ADD: - negated_imm = (sljit_uw)-(sljit_w)imm; + negated_imm = (sljit_uw)-(sljit_sw)imm; if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(reg, dst)) { if (imm <= 0x7) return push_inst16(compiler, ADDSI3 | IMM3(imm) | RD3(dst) | RN3(reg)); @@ -572,7 +573,7 @@ static int emit_op_imm(struct sljit_compiler *compiler, int flags, int dst, slji break; case SLJIT_SUB: if (flags & ARG2_IMM) { - negated_imm = (sljit_uw)-(sljit_w)imm; + negated_imm = (sljit_uw)-(sljit_sw)imm; if (!(flags & KEEP_FLAGS) && IS_2_LO_REGS(reg, dst)) { if (imm <= 0x7) return push_inst16(compiler, SUBSI3 | IMM3(imm) | RD3(dst) | RN3(reg)); @@ -701,9 +702,11 @@ static int emit_op_imm(struct sljit_compiler *compiler, int flags, int dst, slji case SLJIT_MOV: case SLJIT_MOV_UI: case SLJIT_MOV_SI: + case SLJIT_MOV_P: case SLJIT_MOVU: case SLJIT_MOVU_UI: case SLJIT_MOVU_SI: + case SLJIT_MOVU_P: SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1); return push_inst16(compiler, MOV | SET_REGS44(dst, arg2)); case SLJIT_MOV_UB: @@ -885,7 +888,7 @@ static SLJIT_CONST sljit_uw sljit_mem32[12] = { }; /* Helper function. Dst should be reg + value, using at most 1 instruction, flags does not set. */ -static int emit_set_delta(struct sljit_compiler *compiler, int dst, int reg, sljit_w value) +static sljit_si emit_set_delta(struct sljit_compiler *compiler, sljit_si dst, sljit_si reg, sljit_sw value) { if (value >= 0) { if (value <= 0xfff) @@ -906,9 +909,9 @@ static int emit_set_delta(struct sljit_compiler *compiler, int dst, int reg, slj } /* Can perform an operation using at most 1 instruction. */ -static int getput_arg_fast(struct sljit_compiler *compiler, int flags, int reg, int arg, sljit_w argw) +static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw) { - int tmp; + sljit_si tmp; SLJIT_ASSERT(arg & SLJIT_MEM); @@ -991,7 +994,7 @@ static int getput_arg_fast(struct sljit_compiler *compiler, int flags, int reg, /* see getput_arg below. Note: can_cache is called only for binary operators. Those operators always uses word arguments without write back. */ -static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw) +static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw) { /* Simple operation except for updates. */ if ((arg & 0xf0) || !(next_arg & SLJIT_MEM)) @@ -1013,10 +1016,10 @@ static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw) } /* Emit the necessary instructions. See can_cache above. */ -static int getput_arg(struct sljit_compiler *compiler, int flags, int reg, int arg, sljit_w argw, int next_arg, sljit_w next_argw) +static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw) { - int tmp_r; - sljit_w tmp; + sljit_si tmp_r; + sljit_sw tmp; SLJIT_ASSERT(arg & SLJIT_MEM); if (!(next_arg & SLJIT_MEM)) { @@ -1112,7 +1115,7 @@ static int getput_arg(struct sljit_compiler *compiler, int flags, int reg, int a return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(TMP_REG3) | 0); } -static SLJIT_INLINE int emit_op_mem(struct sljit_compiler *compiler, int flags, int reg, int arg, sljit_w argw) +static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw) { if (getput_arg_fast(compiler, flags, reg, arg, argw)) return compiler->error; @@ -1121,15 +1124,26 @@ static SLJIT_INLINE int emit_op_mem(struct sljit_compiler *compiler, int flags, return getput_arg(compiler, flags, reg, arg, argw, 0, 0); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w) { - int size; + if (getput_arg_fast(compiler, flags, reg, arg1, arg1w)) + return compiler->error; + return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w); +} + +/* --------------------------------------------------------------------- */ +/* Entry, exit */ +/* --------------------------------------------------------------------- */ + +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) +{ + sljit_si size; sljit_ins push; CHECK_ERROR(); - check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size); + check_sljit_emit_enter(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; @@ -1146,7 +1160,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i push |= 1 << 7; if (saveds >= 1) push |= 1 << 6; - if (temporaries >= 5) + if (scratches >= 5) push |= 1 << 5; FAIL_IF(saveds >= 3 ? push_inst32(compiler, PUSH_W | (1 << 14) | push) @@ -1166,23 +1180,23 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i } if (args >= 1) - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SAVED_REG1, SLJIT_TEMPORARY_REG1))); + FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SAVED_REG1, SLJIT_SCRATCH_REG1))); if (args >= 2) - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SAVED_REG2, SLJIT_TEMPORARY_REG2))); + FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SAVED_REG2, SLJIT_SCRATCH_REG2))); if (args >= 3) - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SAVED_REG3, SLJIT_TEMPORARY_REG3))); + FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SAVED_REG3, SLJIT_SCRATCH_REG3))); return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { - int size; + sljit_si size; CHECK_ERROR_VOID(); - check_sljit_set_context(compiler, args, temporaries, saveds, local_size); + check_sljit_set_context(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; @@ -1195,13 +1209,12 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, compiler->local_size = local_size; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) { sljit_ins pop; CHECK_ERROR(); check_sljit_emit_return(compiler, op, src, srcw); - ADJUST_LOCAL_OFFSET(src, srcw); FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); @@ -1223,7 +1236,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, pop |= 1 << 7; if (compiler->saveds >= 1) pop |= 1 << 6; - if (compiler->temporaries >= 5) + if (compiler->scratches >= 5) pop |= 1 << 5; return compiler->saveds >= 3 ? push_inst32(compiler, POP_W | (1 << 15) | pop) @@ -1239,8 +1252,8 @@ extern "C" { #endif #if defined(__GNUC__) -extern unsigned int __aeabi_uidivmod(unsigned numerator, unsigned denominator); -extern unsigned int __aeabi_idivmod(unsigned numerator, unsigned denominator); +extern unsigned int __aeabi_uidivmod(unsigned int numerator, int unsigned denominator); +extern int __aeabi_idivmod(int numerator, int denominator); #else #error "Software divmod functions are needed" #endif @@ -1249,7 +1262,7 @@ extern unsigned int __aeabi_idivmod(unsigned numerator, unsigned denominator); } #endif -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) { CHECK_ERROR(); check_sljit_emit_op0(compiler, op); @@ -1265,16 +1278,16 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int case SLJIT_UMUL: case SLJIT_SMUL: return push_inst32(compiler, (op == SLJIT_UMUL ? UMULL : SMULL) - | (reg_map[SLJIT_TEMPORARY_REG2] << 8) - | (reg_map[SLJIT_TEMPORARY_REG1] << 12) - | (reg_map[SLJIT_TEMPORARY_REG1] << 16) - | reg_map[SLJIT_TEMPORARY_REG2]); + | (reg_map[SLJIT_SCRATCH_REG2] << 8) + | (reg_map[SLJIT_SCRATCH_REG1] << 12) + | (reg_map[SLJIT_SCRATCH_REG1] << 16) + | reg_map[SLJIT_SCRATCH_REG2]); case SLJIT_UDIV: case SLJIT_SDIV: - if (compiler->temporaries >= 4) { + 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->temporaries >= 3) + } else if (compiler->scratches >= 3) FAIL_IF(push_inst32(compiler, 0xf84d2d08 /* str r2, [sp, #-8]! */)); #if defined(__GNUC__) FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, @@ -1282,10 +1295,10 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int #else #error "Software divmod functions are needed" #endif - if (compiler->temporaries >= 4) { + 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->temporaries >= 3) + } else if (compiler->scratches >= 3) return push_inst32(compiler, 0xf85d2b08 /* ldr r2, [sp], #8 */); return SLJIT_SUCCESS; } @@ -1293,11 +1306,12 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +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) { - int op_type, dst_r, flags; + sljit_si dst_r, flags; + sljit_si op_flags = GET_ALL_FLAGS(op); CHECK_ERROR(); check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw); @@ -1307,60 +1321,62 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int compiler->cache_arg = 0; compiler->cache_argw = 0; - op_type = GET_OPCODE(op); - dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG1; + dst_r = (dst >= SLJIT_SCRATCH_REG1 && dst <= TMP_REG3) ? dst : TMP_REG1; - if (op_type >= SLJIT_MOV && op_type <= SLJIT_MOVU_SI) { - switch (op_type) { + op = GET_OPCODE(op); + if (op >= SLJIT_MOV && op <= SLJIT_MOVU_P) { + switch (op) { case SLJIT_MOV: case SLJIT_MOV_UI: case SLJIT_MOV_SI: + case SLJIT_MOV_P: flags = WORD_SIZE; break; case SLJIT_MOV_UB: flags = BYTE_SIZE; if (src & SLJIT_IMM) - srcw = (unsigned char)srcw; + srcw = (sljit_ub)srcw; break; case SLJIT_MOV_SB: flags = BYTE_SIZE | SIGNED; if (src & SLJIT_IMM) - srcw = (signed char)srcw; + srcw = (sljit_sb)srcw; break; case SLJIT_MOV_UH: flags = HALF_SIZE; if (src & SLJIT_IMM) - srcw = (unsigned short)srcw; + srcw = (sljit_uh)srcw; break; case SLJIT_MOV_SH: flags = HALF_SIZE | SIGNED; if (src & SLJIT_IMM) - srcw = (signed short)srcw; + srcw = (sljit_sh)srcw; break; case SLJIT_MOVU: case SLJIT_MOVU_UI: case SLJIT_MOVU_SI: + case SLJIT_MOVU_P: flags = WORD_SIZE | UPDATE; break; case SLJIT_MOVU_UB: flags = BYTE_SIZE | UPDATE; if (src & SLJIT_IMM) - srcw = (unsigned char)srcw; + srcw = (sljit_ub)srcw; break; case SLJIT_MOVU_SB: flags = BYTE_SIZE | SIGNED | UPDATE; if (src & SLJIT_IMM) - srcw = (signed char)srcw; + srcw = (sljit_sb)srcw; break; case SLJIT_MOVU_UH: flags = HALF_SIZE | UPDATE; if (src & SLJIT_IMM) - srcw = (unsigned short)srcw; + srcw = (sljit_uh)srcw; break; case SLJIT_MOVU_SH: flags = HALF_SIZE | SIGNED | UPDATE; if (src & SLJIT_IMM) - srcw = (signed short)srcw; + srcw = (sljit_sh)srcw; break; default: SLJIT_ASSERT_STOP(); @@ -1377,7 +1393,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int FAIL_IF(getput_arg(compiler, flags, dst_r, src, srcw, dst, dstw)); } else { if (dst_r != TMP_REG1) - return emit_op_imm(compiler, op_type, dst_r, TMP_REG1, src); + return emit_op_imm(compiler, op, dst_r, TMP_REG1, src); dst_r = src; } @@ -1390,14 +1406,14 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int return SLJIT_SUCCESS; } - if (op_type == SLJIT_NEG) { + if (op == SLJIT_NEG) { #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->skip_checks = 1; #endif - return sljit_emit_op2(compiler, GET_FLAGS(op) | SLJIT_SUB, dst, dstw, SLJIT_IMM, 0, src, srcw); + return sljit_emit_op2(compiler, SLJIT_SUB | op_flags, dst, dstw, SLJIT_IMM, 0, src, srcw); } - flags = (GET_FLAGS(op) ? SET_FLAGS : 0) | ((op & SLJIT_KEEP_FLAGS) ? KEEP_FLAGS : 0); + flags = (GET_FLAGS(op_flags) ? SET_FLAGS : 0) | ((op_flags & SLJIT_KEEP_FLAGS) ? KEEP_FLAGS : 0); if (src & SLJIT_MEM) { if (getput_arg_fast(compiler, WORD_SIZE, TMP_REG2, src, srcw)) FAIL_IF(compiler->error); @@ -1411,7 +1427,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int else srcw = src; - emit_op_imm(compiler, flags | op_type, dst_r, TMP_REG1, srcw); + emit_op_imm(compiler, flags | op, dst_r, TMP_REG1, srcw); if (dst & SLJIT_MEM) { if (getput_arg_fast(compiler, flags | STORE, dst_r, dst, dstw)) @@ -1422,12 +1438,12 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +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) { - int dst_r, flags; + sljit_si dst_r, flags; CHECK_ERROR(); check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w); @@ -1438,7 +1454,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int compiler->cache_arg = 0; compiler->cache_argw = 0; - dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG1; + dst_r = (dst >= SLJIT_SCRATCH_REG1 && dst <= TMP_REG3) ? dst : TMP_REG1; flags = (GET_FLAGS(op) ? SET_FLAGS : 0) | ((op & SLJIT_KEEP_FLAGS) ? KEEP_FLAGS : 0); if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, WORD_SIZE | STORE | ARG_TEST, TMP_REG1, dst, dstw)) @@ -1504,14 +1520,20 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg) { check_sljit_get_register_index(reg); return reg_map[reg]; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, int size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg) +{ + check_sljit_get_float_register_index(reg); + return reg; +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, + void *instruction, sljit_si size) { CHECK_ERROR(); check_sljit_emit_op_custom(compiler, instruction, size); @@ -1526,15 +1548,18 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compile /* Floating point operators */ /* --------------------------------------------------------------------- */ -SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void) { return 1; } -static int emit_fop_mem(struct sljit_compiler *compiler, int flags, int reg, int arg, sljit_w argw) +#define FPU_LOAD (1 << 20) + +static sljit_si emit_fop_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw) { - sljit_w tmp; - sljit_w inst = VSTR | ((flags & STORE) ? 0 : 0x00100000); + sljit_sw tmp; + sljit_uw imm; + sljit_sw inst = VSTR_F32 | (flags & (SLJIT_SINGLE_OP | FPU_LOAD)); SLJIT_ASSERT(arg & SLJIT_MEM); @@ -1545,7 +1570,7 @@ static int emit_fop_mem(struct sljit_compiler *compiler, int flags, int reg, int argw = 0; } - if (arg & 0xf) { + if ((arg & 0xf) && (argw & 0x3) == 0) { if (!(argw & ~0x3fc)) return push_inst32(compiler, inst | 0x800000 | RN4(arg & 0xf) | DD4(reg) | (argw >> 2)); if (!(-argw & ~0x3fc)) @@ -1566,13 +1591,29 @@ static int emit_fop_mem(struct sljit_compiler *compiler, int flags, int reg, int } } + if (arg & 0xf) { + if (emit_set_delta(compiler, TMP_REG1, arg & 0xf, argw) != SLJIT_ERR_UNSUPPORTED) { + FAIL_IF(compiler->error); + return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg)); + } + imm = get_imm(argw & ~0x3fc); + if (imm != INVALID_IMM) { + FAIL_IF(push_inst32(compiler, ADD_WI | RD4(TMP_REG1) | RN4(arg & 0xf) | imm)); + return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg) | ((argw & 0x3fc) >> 2)); + } + imm = get_imm(-argw & ~0x3fc); + if (imm != INVALID_IMM) { + argw = -argw; + FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(arg & 0xf) | imm)); + return push_inst32(compiler, inst | RN4(TMP_REG1) | DD4(reg) | ((argw & 0x3fc) >> 2)); + } + } + compiler->cache_arg = arg; compiler->cache_argw = argw; if (SLJIT_UNLIKELY(!(arg & 0xf))) FAIL_IF(load_immediate(compiler, TMP_REG3, argw)); - else if (emit_set_delta(compiler, TMP_REG3, arg & 0xf, argw) != SLJIT_ERR_UNSUPPORTED) - FAIL_IF(compiler->error); else { FAIL_IF(load_immediate(compiler, TMP_REG3, argw)); if (arg & 0xf) @@ -1581,129 +1622,137 @@ static int emit_fop_mem(struct sljit_compiler *compiler, int flags, int reg, int return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG3) | DD4(reg)); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - int dst_r; + sljit_si dst_r; CHECK_ERROR(); check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw); + SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100), float_transfer_bit_error); compiler->cache_arg = 0; compiler->cache_argw = 0; + op ^= SLJIT_SINGLE_OP; - if (GET_OPCODE(op) == SLJIT_FCMP) { + if (GET_OPCODE(op) == SLJIT_CMPD) { if (dst & SLJIT_MEM) { - emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw); + emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, dst, dstw); dst = TMP_FREG1; } if (src & SLJIT_MEM) { - emit_fop_mem(compiler, 0, TMP_FREG2, src, srcw); + emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG2, src, srcw); src = TMP_FREG2; } - FAIL_IF(push_inst32(compiler, VCMP_F64 | DD4(dst) | DM4(src))); + FAIL_IF(push_inst32(compiler, VCMP_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst) | DM4(src))); return push_inst32(compiler, VMRS); } - dst_r = (dst >= SLJIT_FLOAT_REG1 && dst <= SLJIT_FLOAT_REG4) ? dst : TMP_FREG1; + dst_r = (dst > SLJIT_FLOAT_REG6) ? TMP_FREG1 : dst; if (src & SLJIT_MEM) { - emit_fop_mem(compiler, 0, dst_r, src, srcw); + emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, dst_r, src, srcw); src = dst_r; } switch (GET_OPCODE(op)) { - case SLJIT_FMOV: + case SLJIT_MOVD: if (src != dst_r) - FAIL_IF(push_inst32(compiler, VMOV_F64 | DD4(dst_r) | DM4(src))); + FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DM4(src))); break; - case SLJIT_FNEG: - FAIL_IF(push_inst32(compiler, VNEG_F64 | DD4(dst_r) | DM4(src))); + case SLJIT_NEGD: + FAIL_IF(push_inst32(compiler, VNEG_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DM4(src))); break; - case SLJIT_FABS: - FAIL_IF(push_inst32(compiler, VABS_F64 | DD4(dst_r) | DM4(src))); + case SLJIT_ABSD: + FAIL_IF(push_inst32(compiler, VABS_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DM4(src))); break; } if (dst & SLJIT_MEM) - return emit_fop_mem(compiler, STORE, TMP_FREG1, dst, dstw); + return emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), TMP_FREG1, dst, dstw); return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(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) { - int dst_r; + sljit_si dst_r; CHECK_ERROR(); check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w); compiler->cache_arg = 0; compiler->cache_argw = 0; + op ^= SLJIT_SINGLE_OP; - dst_r = (dst >= SLJIT_FLOAT_REG1 && dst <= SLJIT_FLOAT_REG4) ? dst : TMP_FREG1; + dst_r = (dst > SLJIT_FLOAT_REG6) ? TMP_FREG1 : dst; if (src1 & SLJIT_MEM) { - emit_fop_mem(compiler, 0, TMP_FREG1, src1, src1w); + emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, src1, src1w); src1 = TMP_FREG1; } if (src2 & SLJIT_MEM) { - emit_fop_mem(compiler, 0, TMP_FREG2, src2, src2w); + emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG2, src2, src2w); src2 = TMP_FREG2; } switch (GET_OPCODE(op)) { - case SLJIT_FADD: - FAIL_IF(push_inst32(compiler, VADD_F64 | DD4(dst_r) | DN4(src1) | DM4(src2))); + case SLJIT_ADDD: + FAIL_IF(push_inst32(compiler, VADD_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DN4(src1) | DM4(src2))); break; - case SLJIT_FSUB: - FAIL_IF(push_inst32(compiler, VSUB_F64 | DD4(dst_r) | DN4(src1) | DM4(src2))); + case SLJIT_SUBD: + FAIL_IF(push_inst32(compiler, VSUB_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DN4(src1) | DM4(src2))); break; - case SLJIT_FMUL: - FAIL_IF(push_inst32(compiler, VMUL_F64 | DD4(dst_r) | DN4(src1) | DM4(src2))); + case SLJIT_MULD: + FAIL_IF(push_inst32(compiler, VMUL_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DN4(src1) | DM4(src2))); break; - case SLJIT_FDIV: - FAIL_IF(push_inst32(compiler, VDIV_F64 | DD4(dst_r) | DN4(src1) | DM4(src2))); + case SLJIT_DIVD: + FAIL_IF(push_inst32(compiler, VDIV_F32 | (op & SLJIT_SINGLE_OP) | DD4(dst_r) | DN4(src1) | DM4(src2))); break; } if (dst & SLJIT_MEM) - return emit_fop_mem(compiler, STORE, TMP_FREG1, dst, dstw); + return emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), TMP_FREG1, dst, dstw); return SLJIT_SUCCESS; } +#undef FPU_LOAD + /* --------------------------------------------------------------------- */ /* Other instructions */ /* --------------------------------------------------------------------- */ -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw) +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); ADJUST_LOCAL_OFFSET(dst, dstw); - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) - return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG3)); - else if (dst & SLJIT_MEM) { - if (getput_arg_fast(compiler, WORD_SIZE | STORE, TMP_REG3, dst, dstw)) - return compiler->error; - FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG2, TMP_REG3))); - compiler->cache_arg = 0; - compiler->cache_argw = 0; - return getput_arg(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, 0, 0); - } + /* For UNUSED dst. Uncommon, but possible. */ + if (dst == SLJIT_UNUSED) + return SLJIT_SUCCESS; - return SLJIT_SUCCESS; + if (dst <= TMP_REG3) + return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG3)); + + /* Memory. */ + if (getput_arg_fast(compiler, WORD_SIZE | STORE, TMP_REG3, dst, dstw)) + return compiler->error; + /* TMP_REG3 is used for caching. */ + FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG2, TMP_REG3))); + compiler->cache_arg = 0; + compiler->cache_argw = 0; + return getput_arg(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, 0, 0); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw) +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); ADJUST_LOCAL_OFFSET(src, srcw); - if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) + if (src <= TMP_REG3) FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG3, src))); else if (src & SLJIT_MEM) { if (getput_arg_fast(compiler, WORD_SIZE, TMP_REG3, src, srcw)) @@ -1724,7 +1773,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compi /* Conditional instructions */ /* --------------------------------------------------------------------- */ -static sljit_uw get_cc(int type) +static sljit_uw get_cc(sljit_si type) { switch (type) { case SLJIT_C_EQUAL: @@ -1766,11 +1815,11 @@ static sljit_uw get_cc(int type) return 0xd; case SLJIT_C_OVERFLOW: - case SLJIT_C_FLOAT_NAN: + case SLJIT_C_FLOAT_UNORDERED: return 0x6; case SLJIT_C_NOT_OVERFLOW: - case SLJIT_C_FLOAT_NOT_NAN: + case SLJIT_C_FLOAT_ORDERED: return 0x7; default: /* SLJIT_JUMP */ @@ -1794,10 +1843,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi return label; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, int type) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type) { struct sljit_jump *jump; - int cc; + sljit_si cc; CHECK_ERROR_PTR(); check_sljit_emit_jump(compiler, type); @@ -1810,7 +1859,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile /* In ARM, we don't need to touch the arguments. */ PTR_FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0)); if (type < SLJIT_JUMP) { - jump->flags |= IS_CONDITIONAL; + jump->flags |= IS_COND; cc = get_cc(type); jump->flags |= cc << 8; PTR_FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); @@ -1827,7 +1876,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile return jump; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, int type, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw) { struct sljit_jump *jump; @@ -1847,7 +1896,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i FAIL_IF(push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(TMP_REG1))); } else { - if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) + if (src <= TMP_REG3) return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(src)); FAIL_IF(emit_op_mem(compiler, WORD_SIZE, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, src, srcw)); @@ -1857,58 +1906,84 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compiler, int op, int dst, sljit_w dstw, int type) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw, + sljit_si type) { - int dst_r; + sljit_si dst_r, flags = GET_ALL_FLAGS(op); + sljit_ins ins; sljit_uw cc; CHECK_ERROR(); - check_sljit_emit_cond_value(compiler, op, dst, dstw, type); + check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type); ADJUST_LOCAL_OFFSET(dst, dstw); + ADJUST_LOCAL_OFFSET(src, srcw); if (dst == SLJIT_UNUSED) return SLJIT_SUCCESS; + op = GET_OPCODE(op); cc = get_cc(type); - if (GET_OPCODE(op) == SLJIT_OR && dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { + dst_r = (dst <= TMP_REG3) ? dst : TMP_REG2; + + if (op < SLJIT_ADD) { + FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4)); + if (reg_map[dst_r] > 7) { + FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 1)); + FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 0)); + } else { + FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 1)); + FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 0)); + } + return dst_r == TMP_REG2 ? emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw) : SLJIT_SUCCESS; + } + + ins = (op == SLJIT_AND ? ANDI : (op == SLJIT_OR ? ORRI : EORI)); + if ((op == SLJIT_OR || op == SLJIT_XOR) && dst <= TMP_REG3 && dst == src) { + /* Does not change the other bits. */ FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8)); - FAIL_IF(push_inst32(compiler, ORRI | RN4(dst) | RD4(dst) | 0x1)); - if (op & SLJIT_SET_E) { + FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst) | 1)); + if (flags & SLJIT_SET_E) { + /* The condition must always be set, even if the ORRI/EORI is not executed above. */ if (reg_map[dst] <= 7) - return push_inst16(compiler, ORRS | RD3(dst) | RN3(dst)); - return push_inst32(compiler, ORR_W | SET_FLAGS | RD4(TMP_REG1) | RN4(dst) | RM4(dst)); + return push_inst16(compiler, MOVS | RD3(TMP_REG1) | RN3(dst)); + return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst)); } return SLJIT_SUCCESS; } - dst_r = TMP_REG2; - if (op == SLJIT_MOV && dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS && reg_map[dst] <= 7) - dst_r = dst; - - FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4)); - FAIL_IF(push_inst16(compiler, MOVSI | 0x1 | RDN3(dst_r))); - FAIL_IF(push_inst16(compiler, MOVSI | 0x0 | RDN3(dst_r))); - - if (dst_r == TMP_REG2) { - if (GET_OPCODE(op) == SLJIT_OR) { -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) - compiler->skip_checks = 1; -#endif - return sljit_emit_op2(compiler, op, dst, dstw, dst, dstw, TMP_REG2, 0); - } - if (dst & SLJIT_MEM) - return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw); - else - return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG2)); + compiler->cache_arg = 0; + compiler->cache_argw = 0; + if (src & SLJIT_MEM) { + FAIL_IF(emit_op_mem2(compiler, WORD_SIZE, TMP_REG1, src, srcw, dst, dstw)); + src = TMP_REG1; + srcw = 0; + } else if (src & SLJIT_IMM) { + FAIL_IF(load_immediate(compiler, TMP_REG1, srcw)); + src = TMP_REG1; + srcw = 0; } + FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4)); + FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst_r) | 1)); + FAIL_IF(push_inst32(compiler, ins | RN4(src) | RD4(dst_r) | 0)); + if (dst_r == TMP_REG2) + FAIL_IF(emit_op_mem2(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, 0, 0)); + + if (flags & SLJIT_SET_E) { + /* The condition must always be set, even if the ORR/EORI is not executed above. */ + if (reg_map[dst_r] <= 7) + return push_inst16(compiler, MOVS | RD3(TMP_REG1) | RN3(dst_r)); + return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst_r)); + } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w init_value) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value) { struct sljit_const *const_; - int dst_r; + sljit_si dst_r; CHECK_ERROR_PTR(); check_sljit_emit_const(compiler, dst, dstw, init_value); @@ -1918,7 +1993,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi PTR_FAIL_IF(!const_); set_const(const_, compiler); - dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG1; + dst_r = (dst <= TMP_REG3) ? dst : TMP_REG1; PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, init_value)); if (dst & SLJIT_MEM) @@ -1931,7 +2006,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad inline_set_jump_addr(addr, new_addr, 1); } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant) { sljit_uh* inst = (sljit_uh*)addr; modify_imm32_const(inst, new_constant); diff --git a/src/3rd/pcre/sjarmv5.c b/src/3rd/pcre/sjarmv5.c index 5dc555ce75..e3ca3d9bb1 100644 --- a/src/3rd/pcre/sjarmv5.c +++ b/src/3rd/pcre/sjarmv5.c @@ -24,7 +24,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() +SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void) { #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) return "ARMv7" SLJIT_CPUINFO; @@ -41,8 +41,8 @@ SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() #define TMP_REG3 (SLJIT_NO_REGISTERS + 3) #define TMP_PC (SLJIT_NO_REGISTERS + 4) -#define TMP_FREG1 (SLJIT_FLOAT_REG4 + 1) -#define TMP_FREG2 (SLJIT_FLOAT_REG4 + 2) +#define TMP_FREG1 (0) +#define TMP_FREG2 (SLJIT_FLOAT_REG6 + 1) /* In ARM instruction words. Cache lines are usually 32 byte aligned. */ @@ -52,11 +52,11 @@ SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() #define ALIGN_INSTRUCTION(ptr) \ (sljit_uw*)(((sljit_uw)(ptr) + (CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1) & ~((CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1)) #define MAX_DIFFERENCE(max_diff) \ - (((max_diff) / (int)sizeof(sljit_uw)) - (CONST_POOL_ALIGNMENT - 1)) + (((max_diff) / (sljit_si)sizeof(sljit_uw)) - (CONST_POOL_ALIGNMENT - 1)) /* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { - 0, 0, 1, 2, 10, 11, 4, 5, 6, 7, 8, 13, 3, 12, 14, 15 + 0, 0, 1, 2, 10, 11, 4, 5, 6, 7, 8, 13, 3, 12, 14, 15 }; #define RM(rm) (reg_map[rm]) @@ -99,16 +99,16 @@ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { #define SMULL 0xe0c00090 #define SUB_DP 0x2 #define UMULL 0xe0800090 -#define VABS_F64 0xeeb00bc0 -#define VADD_F64 0xee300b00 -#define VCMP_F64 0xeeb40b40 -#define VDIV_F64 0xee800b00 -#define VMOV_F64 0xeeb00b40 +#define VABS_F32 0xeeb00ac0 +#define VADD_F32 0xee300a00 +#define VCMP_F32 0xeeb40a40 +#define VDIV_F32 0xee800a00 +#define VMOV_F32 0xeeb00a40 #define VMRS 0xeef1fa10 -#define VMUL_F64 0xee200b00 -#define VNEG_F64 0xeeb10b40 -#define VSTR 0xed000b00 -#define VSUB_F64 0xee300b40 +#define VMUL_F32 0xee200a00 +#define VNEG_F32 0xeeb10a40 +#define VSTR_F32 0xed000a00 +#define VSUB_F32 0xee300a40 #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) /* Arm v7 specific instructions. */ @@ -122,13 +122,13 @@ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) -static int push_cpool(struct sljit_compiler *compiler) +static sljit_si push_cpool(struct sljit_compiler *compiler) { /* Pushing the constant pool into the instruction stream. */ sljit_uw* inst; sljit_uw* cpool_ptr; sljit_uw* cpool_end; - int i; + sljit_si i; /* The label could point the address after the constant pool. */ if (compiler->last_label && compiler->last_label->size == compiler->size) @@ -160,7 +160,7 @@ static int push_cpool(struct sljit_compiler *compiler) return SLJIT_SUCCESS; } -static int push_inst(struct sljit_compiler *compiler, sljit_uw inst) +static sljit_si push_inst(struct sljit_compiler *compiler, sljit_uw inst) { sljit_uw* ptr; @@ -174,7 +174,7 @@ static int push_inst(struct sljit_compiler *compiler, sljit_uw inst) return SLJIT_SUCCESS; } -static int push_inst_with_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal) +static sljit_si push_inst_with_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal) { sljit_uw* ptr; sljit_uw cpool_index = CPOOL_SIZE; @@ -224,7 +224,7 @@ static int push_inst_with_literal(struct sljit_compiler *compiler, sljit_uw inst return SLJIT_SUCCESS; } -static int push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal) +static sljit_si push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal) { sljit_uw* ptr; if (SLJIT_UNLIKELY((compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)) || compiler->cpool_fill >= CPOOL_SIZE)) @@ -244,7 +244,7 @@ static int push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_ return SLJIT_SUCCESS; } -static SLJIT_INLINE int prepare_blx(struct sljit_compiler *compiler) +static SLJIT_INLINE sljit_si prepare_blx(struct sljit_compiler *compiler) { /* Place for at least two instruction (doesn't matter whether the first has a literal). */ if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4088))) @@ -252,7 +252,7 @@ static SLJIT_INLINE int prepare_blx(struct sljit_compiler *compiler) return SLJIT_SUCCESS; } -static SLJIT_INLINE int emit_blx(struct sljit_compiler *compiler) +static SLJIT_INLINE sljit_si emit_blx(struct sljit_compiler *compiler) { /* Must follow tightly the previous instruction (to be able to convert it to bl instruction). */ SLJIT_ASSERT(compiler->cpool_diff == CONST_POOL_EMPTY || compiler->size - compiler->cpool_diff < MAX_DIFFERENCE(4092)); @@ -282,7 +282,7 @@ static sljit_uw patch_pc_relative_loads(sljit_uw *last_pc_patch, sljit_uw *code_ /* Must be a load instruction with immediate offset. */ SLJIT_ASSERT(ind < cpool_size && !(*last_pc_patch & (1 << 25)) && (*last_pc_patch & (1 << 20))); - if ((int)const_pool[ind] < 0) { + if ((sljit_si)const_pool[ind] < 0) { const_pool[ind] = counter; ind = counter; counter++; @@ -307,24 +307,24 @@ static sljit_uw patch_pc_relative_loads(sljit_uw *last_pc_patch, sljit_uw *code_ /* In some rare ocasions we may need future patches. The probability is close to 0 in practice. */ struct future_patch { struct future_patch* next; - int index; - int value; + sljit_si index; + sljit_si value; }; -static SLJIT_INLINE int resolve_const_pool_index(struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr) +static SLJIT_INLINE sljit_si resolve_const_pool_index(struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr) { - int value; + sljit_si value; struct future_patch *curr_patch, *prev_patch; /* Using the values generated by patch_pc_relative_loads. */ if (!*first_patch) - value = (int)cpool_start_address[cpool_current_index]; + value = (sljit_si)cpool_start_address[cpool_current_index]; else { curr_patch = *first_patch; prev_patch = 0; while (1) { if (!curr_patch) { - value = (int)cpool_start_address[cpool_current_index]; + value = (sljit_si)cpool_start_address[cpool_current_index]; break; } if ((sljit_uw)curr_patch->index == cpool_current_index) { @@ -364,7 +364,7 @@ static SLJIT_INLINE int resolve_const_pool_index(struct future_patch **first_pat #else -static int push_inst(struct sljit_compiler *compiler, sljit_uw inst) +static sljit_si push_inst(struct sljit_compiler *compiler, sljit_uw inst) { sljit_uw* ptr; @@ -375,7 +375,7 @@ static int push_inst(struct sljit_compiler *compiler, sljit_uw inst) return SLJIT_SUCCESS; } -static SLJIT_INLINE int emit_imm(struct sljit_compiler *compiler, int reg, sljit_w imm) +static SLJIT_INLINE sljit_si emit_imm(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm) { FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff))); return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | ((imm >> 16) & 0xfff)); @@ -383,9 +383,9 @@ static SLJIT_INLINE int emit_imm(struct sljit_compiler *compiler, int reg, sljit #endif -static SLJIT_INLINE int detect_jump_type(struct sljit_jump *jump, sljit_uw *code_ptr, sljit_uw *code) +static SLJIT_INLINE sljit_si detect_jump_type(struct sljit_jump *jump, sljit_uw *code_ptr, sljit_uw *code) { - sljit_w diff; + sljit_sw diff; if (jump->flags & SLJIT_REWRITABLE_JUMP) return 0; @@ -395,17 +395,16 @@ static SLJIT_INLINE int detect_jump_type(struct sljit_jump *jump, sljit_uw *code code_ptr--; if (jump->flags & JUMP_ADDR) - diff = ((sljit_w)jump->u.target - (sljit_w)(code_ptr + 2)); + diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2)); else { SLJIT_ASSERT(jump->flags & JUMP_LABEL); - diff = ((sljit_w)(code + jump->u.label->size) - (sljit_w)(code_ptr + 2)); + diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2)); } /* Branch to Thumb code has not been optimized yet. */ if (diff & 0x3) return 0; - diff >>= 2; if (jump->flags & IS_BL) { if (diff <= 0x01ffffff && diff >= -0x02000000) { *code_ptr = (BL - CONDITIONAL) | (*(code_ptr + 1) & COND_MASK); @@ -421,17 +420,16 @@ static SLJIT_INLINE int detect_jump_type(struct sljit_jump *jump, sljit_uw *code } #else if (jump->flags & JUMP_ADDR) - diff = ((sljit_w)jump->u.target - (sljit_w)code_ptr); + diff = ((sljit_sw)jump->u.target - (sljit_sw)code_ptr); else { SLJIT_ASSERT(jump->flags & JUMP_LABEL); - diff = ((sljit_w)(code + jump->u.label->size) - (sljit_w)code_ptr); + diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)code_ptr); } /* Branch to Thumb code has not been optimized yet. */ if (diff & 0x3) return 0; - diff >>= 2; if (diff <= 0x01ffffff && diff >= -0x02000000) { code_ptr -= 2; *code_ptr = ((jump->flags & IS_BL) ? (BL - CONDITIONAL) : (B - CONDITIONAL)) | (code_ptr[2] & COND_MASK); @@ -442,14 +440,14 @@ static SLJIT_INLINE int detect_jump_type(struct sljit_jump *jump, sljit_uw *code return 0; } -static SLJIT_INLINE void inline_set_jump_addr(sljit_uw addr, sljit_uw new_addr, int flush) +static SLJIT_INLINE void inline_set_jump_addr(sljit_uw addr, sljit_uw new_addr, sljit_si flush) { #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) sljit_uw *ptr = (sljit_uw*)addr; sljit_uw *inst = (sljit_uw*)ptr[0]; sljit_uw mov_pc = ptr[1]; - int bl = (mov_pc & 0x0000f000) != RD(TMP_PC); - sljit_w diff = (sljit_w)(((sljit_w)new_addr - (sljit_w)(inst + 2)) >> 2); + sljit_si bl = (mov_pc & 0x0000f000) != RD(TMP_PC); + sljit_sw diff = (sljit_sw)(((sljit_sw)new_addr - (sljit_sw)(inst + 2)) >> 2); if (diff <= 0x7fffff && diff >= -0x800000) { /* Turn to branch. */ @@ -498,9 +496,9 @@ static SLJIT_INLINE void inline_set_jump_addr(sljit_uw addr, sljit_uw new_addr, #endif } -static sljit_uw get_immediate(sljit_uw imm); +static sljit_uw get_imm(sljit_uw imm); -static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_w new_constant, int flush) +static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw new_constant, sljit_si flush) { #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) sljit_uw *ptr = (sljit_uw*)addr; @@ -508,7 +506,7 @@ static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_w new_constant, i sljit_uw ldr_literal = ptr[1]; sljit_uw src2; - src2 = get_immediate(new_constant); + src2 = get_imm(new_constant); if (src2) { *inst = 0xe3a00000 | (ldr_literal & 0xf000) | src2; if (flush) { @@ -517,7 +515,7 @@ static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_w new_constant, i return; } - src2 = get_immediate(~new_constant); + src2 = get_imm(~new_constant); if (src2) { *inst = 0xe3e00000 | (ldr_literal & 0xf000) | src2; if (flush) { @@ -730,12 +728,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil if (jump->flags & PATCH_B) { if (!(jump->flags & JUMP_ADDR)) { SLJIT_ASSERT(jump->flags & JUMP_LABEL); - SLJIT_ASSERT(((sljit_w)jump->u.label->addr - (sljit_w)(buf_ptr + 2)) <= 0x01ffffff && ((sljit_w)jump->u.label->addr - (sljit_w)(buf_ptr + 2)) >= -0x02000000); - *buf_ptr |= (((sljit_w)jump->u.label->addr - (sljit_w)(buf_ptr + 2)) >> 2) & 0x00ffffff; + SLJIT_ASSERT(((sljit_sw)jump->u.label->addr - (sljit_sw)(buf_ptr + 2)) <= 0x01ffffff && ((sljit_sw)jump->u.label->addr - (sljit_sw)(buf_ptr + 2)) >= -0x02000000); + *buf_ptr |= (((sljit_sw)jump->u.label->addr - (sljit_sw)(buf_ptr + 2)) >> 2) & 0x00ffffff; } else { - SLJIT_ASSERT(((sljit_w)jump->u.target - (sljit_w)(buf_ptr + 2)) <= 0x01ffffff && ((sljit_w)jump->u.target - (sljit_w)(buf_ptr + 2)) >= -0x02000000); - *buf_ptr |= (((sljit_w)jump->u.target - (sljit_w)(buf_ptr + 2)) >> 2) & 0x00ffffff; + SLJIT_ASSERT(((sljit_sw)jump->u.target - (sljit_sw)(buf_ptr + 2)) <= 0x01ffffff && ((sljit_sw)jump->u.target - (sljit_sw)(buf_ptr + 2)) >= -0x02000000); + *buf_ptr |= (((sljit_sw)jump->u.target - (sljit_sw)(buf_ptr + 2)) >> 2) & 0x00ffffff; } } else if (jump->flags & SLJIT_REWRITABLE_JUMP) { @@ -785,14 +783,18 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil } #endif - SLJIT_ASSERT(code_ptr - code <= (int)size); + SLJIT_ASSERT(code_ptr - code <= (sljit_si)size); - SLJIT_CACHE_FLUSH(code, code_ptr); compiler->error = SLJIT_ERR_COMPILED; - compiler->executable_size = size * sizeof(sljit_uw); + compiler->executable_size = (code_ptr - code) * sizeof(sljit_uw); + SLJIT_CACHE_FLUSH(code, code_ptr); return code; } +/* --------------------------------------------------------------------- */ +/* Entry, exit */ +/* --------------------------------------------------------------------- */ + /* emit_op inp_flags. WRITE_BACK must be the first, since it is a flag. */ #define WRITE_BACK 0x01 @@ -815,20 +817,20 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil #define EMIT_DATA_PROCESS_INS(opcode, set_flags, dst, src1, src2) \ (0xe0000000 | ((opcode) << 21) | (set_flags) | RD(dst) | RN(src1) | (src2)) -static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w); +static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si inp_flags, + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w); -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { - int size; + sljit_si size; sljit_uw push; CHECK_ERROR(); - check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size); + check_sljit_emit_enter(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; @@ -837,9 +839,9 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i /* Push saved registers, temporary registers stmdb sp!, {..., lr} */ push = PUSH | (1 << 14); - if (temporaries >= 5) + if (scratches >= 5) push |= 1 << 11; - if (temporaries >= 4) + if (scratches >= 4) push |= 1 << 10; if (saveds >= 5) push |= 1 << 8; @@ -855,8 +857,8 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i /* Stack must be aligned to 8 bytes: */ size = (1 + saveds) * sizeof(sljit_uw); - if (temporaries >= 4) - size += (temporaries - 3) * sizeof(sljit_uw); + if (scratches >= 4) + size += (scratches - 3) * sizeof(sljit_uw); local_size += size; local_size = (local_size + 7) & ~7; local_size -= size; @@ -865,44 +867,43 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i FAIL_IF(emit_op(compiler, SLJIT_SUB, ALLOW_IMM, SLJIT_LOCALS_REG, 0, SLJIT_LOCALS_REG, 0, SLJIT_IMM, local_size)); if (args >= 1) - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, SLJIT_SAVED_REG1, SLJIT_UNUSED, RM(SLJIT_TEMPORARY_REG1))); + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, SLJIT_SAVED_REG1, SLJIT_UNUSED, RM(SLJIT_SCRATCH_REG1))); if (args >= 2) - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, SLJIT_SAVED_REG2, SLJIT_UNUSED, RM(SLJIT_TEMPORARY_REG2))); + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, SLJIT_SAVED_REG2, SLJIT_UNUSED, RM(SLJIT_SCRATCH_REG2))); if (args >= 3) - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, SLJIT_SAVED_REG3, SLJIT_UNUSED, RM(SLJIT_TEMPORARY_REG3))); + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, SLJIT_SAVED_REG3, SLJIT_UNUSED, RM(SLJIT_SCRATCH_REG3))); return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { - int size; + sljit_si size; CHECK_ERROR_VOID(); - check_sljit_set_context(compiler, args, temporaries, saveds, local_size); + check_sljit_set_context(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; #endif size = (1 + saveds) * sizeof(sljit_uw); - if (temporaries >= 4) - size += (temporaries - 3) * sizeof(sljit_uw); + if (scratches >= 4) + size += (scratches - 3) * sizeof(sljit_uw); local_size += size; local_size = (local_size + 7) & ~7; local_size -= size; compiler->local_size = local_size; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) { sljit_uw pop; CHECK_ERROR(); check_sljit_emit_return(compiler, op, src, srcw); - ADJUST_LOCAL_OFFSET(src, srcw); FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); @@ -912,9 +913,9 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, pop = POP | (1 << 15); /* Push saved registers, temporary registers ldmia sp!, {..., pc} */ - if (compiler->temporaries >= 5) + if (compiler->scratches >= 5) pop |= 1 << 11; - if (compiler->temporaries >= 4) + if (compiler->scratches >= 4) pop |= 1 << 10; if (compiler->saveds >= 5) pop |= 1 << 8; @@ -939,7 +940,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, w/b/h/N - word/byte/half/NOT allowed (2 bit) It contans 16 items, but not all are different. */ -static sljit_w data_transfer_insts[16] = { +static sljit_sw data_transfer_insts[16] = { /* s u w */ 0xe5000000 /* str */, /* s u b */ 0xe5400000 /* strb */, /* s u h */ 0xe10000b0 /* strh */, @@ -1005,12 +1006,80 @@ static sljit_w data_transfer_insts[16] = { } \ return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, flags & SET_FLAGS, dst, SLJIT_UNUSED, (reg_map[(flags & ARGS_SWAPPED) ? src1 : src2] << 8) | (opcode << 5) | 0x10 | ((flags & ARGS_SWAPPED) ? reg_map[src2] : reg_map[src1]))); -static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags, - int dst, int src1, int src2) +static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags, + sljit_si dst, sljit_si src1, sljit_si src2) { - sljit_w mul_inst; + sljit_sw mul_inst; switch (GET_OPCODE(op)) { + case SLJIT_MOV: + SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); + if (dst != src2) { + if (src2 & SRC2_IMM) { + if (flags & INV_IMM) + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2); + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2); + } + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, reg_map[src2]); + } + return SLJIT_SUCCESS; + + case SLJIT_MOV_UB: + case SLJIT_MOV_SB: + SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); + if ((flags & (REG_DEST | REG_SOURCE)) == (REG_DEST | REG_SOURCE)) { +#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) + if (op == SLJIT_MOV_UB) + return push_inst(compiler, EMIT_DATA_PROCESS_INS(AND_DP, 0, dst, src2, SRC2_IMM | 0xff)); + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | reg_map[src2])); + return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | (op == SLJIT_MOV_UB ? 0x20 : 0x40) | reg_map[dst])); +#else + return push_inst(compiler, (op == SLJIT_MOV_UB ? UXTB : SXTB) | RD(dst) | RM(src2)); +#endif + } + else if (dst != src2) { + SLJIT_ASSERT(src2 & SRC2_IMM); + if (flags & INV_IMM) + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2); + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2); + } + return SLJIT_SUCCESS; + + case SLJIT_MOV_UH: + case SLJIT_MOV_SH: + SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); + if ((flags & (REG_DEST | REG_SOURCE)) == (REG_DEST | REG_SOURCE)) { +#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | reg_map[src2])); + return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | (op == SLJIT_MOV_UH ? 0x20 : 0x40) | reg_map[dst])); +#else + return push_inst(compiler, (op == SLJIT_MOV_UH ? UXTH : SXTH) | RD(dst) | RM(src2)); +#endif + } + else if (dst != src2) { + SLJIT_ASSERT(src2 & SRC2_IMM); + if (flags & INV_IMM) + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2); + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2); + } + return SLJIT_SUCCESS; + + case SLJIT_NOT: + if (src2 & SRC2_IMM) { + if (flags & INV_IMM) + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2); + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2); + } + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, RM(src2)); + + case SLJIT_CLZ: + SLJIT_ASSERT(!(flags & INV_IMM)); + SLJIT_ASSERT(!(src2 & SRC2_IMM)); + FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(src2))); + if (flags & SET_FLAGS) + EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(CMP_DP, SLJIT_UNUSED, dst, SRC2_IMM); + return SLJIT_SUCCESS; + case SLJIT_ADD: SLJIT_ASSERT(!(flags & INV_IMM)); EMIT_DATA_PROCESS_INS_AND_RETURN(ADD_DP); @@ -1080,74 +1149,6 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, case SLJIT_ASHR: EMIT_SHIFT_INS_AND_RETURN(2); - - case SLJIT_MOV: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); - if (dst != src2) { - if (src2 & SRC2_IMM) { - if (flags & INV_IMM) - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2); - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2); - } - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, reg_map[src2]); - } - return SLJIT_SUCCESS; - - case SLJIT_MOV_UB: - case SLJIT_MOV_SB: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); - if ((flags & (REG_DEST | REG_SOURCE)) == (REG_DEST | REG_SOURCE)) { -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - if (op == SLJIT_MOV_UB) - return push_inst(compiler, EMIT_DATA_PROCESS_INS(AND_DP, 0, dst, src2, SRC2_IMM | 0xff)); - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | reg_map[src2])); - return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (24 << 7) | (op == SLJIT_MOV_UB ? 0x20 : 0x40) | reg_map[dst])); -#else - return push_inst(compiler, (op == SLJIT_MOV_UB ? UXTB : SXTB) | RD(dst) | RM(src2)); -#endif - } - else if (dst != src2) { - SLJIT_ASSERT(src2 & SRC2_IMM); - if (flags & INV_IMM) - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2); - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2); - } - return SLJIT_SUCCESS; - - case SLJIT_MOV_UH: - case SLJIT_MOV_SH: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED)); - if ((flags & (REG_DEST | REG_SOURCE)) == (REG_DEST | REG_SOURCE)) { -#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | reg_map[src2])); - return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, (16 << 7) | (op == SLJIT_MOV_UH ? 0x20 : 0x40) | reg_map[dst])); -#else - return push_inst(compiler, (op == SLJIT_MOV_UH ? UXTH : SXTH) | RD(dst) | RM(src2)); -#endif - } - else if (dst != src2) { - SLJIT_ASSERT(src2 & SRC2_IMM); - if (flags & INV_IMM) - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2); - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2); - } - return SLJIT_SUCCESS; - - case SLJIT_NOT: - if (src2 & SRC2_IMM) { - if (flags & INV_IMM) - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MOV_DP, dst, SLJIT_UNUSED, src2); - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, src2); - } - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(MVN_DP, dst, SLJIT_UNUSED, RM(src2)); - - case SLJIT_CLZ: - SLJIT_ASSERT(!(flags & INV_IMM)); - SLJIT_ASSERT(!(src2 & SRC2_IMM)); - FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(src2))); - if (flags & SET_FLAGS) - EMIT_FULL_DATA_PROCESS_INS_AND_RETURN(CMP_DP, SLJIT_UNUSED, dst, SRC2_IMM); - return SLJIT_SUCCESS; } SLJIT_ASSERT_STOP(); return SLJIT_SUCCESS; @@ -1159,9 +1160,9 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, /* Tests whether the immediate can be stored in the 12 bit imm field. Returns with 0 if not possible. */ -static sljit_uw get_immediate(sljit_uw imm) +static sljit_uw get_imm(sljit_uw imm) { - int rol; + sljit_si rol; if (imm <= 0xff) return SRC2_IMM | imm; @@ -1197,12 +1198,12 @@ static sljit_uw get_immediate(sljit_uw imm) } #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) -static int generate_int(struct sljit_compiler *compiler, int reg, sljit_uw imm, int positive) +static sljit_si generate_int(struct sljit_compiler *compiler, sljit_si reg, sljit_uw imm, sljit_si positive) { sljit_uw mask; sljit_uw imm1; sljit_uw imm2; - int rol; + sljit_si rol; /* Step1: Search a zero byte (8 continous zero bit). */ mask = 0xff000000; @@ -1308,7 +1309,7 @@ static int generate_int(struct sljit_compiler *compiler, int reg, sljit_uw imm, } #endif -static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_uw imm) +static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_uw imm) { sljit_uw tmp; @@ -1318,13 +1319,13 @@ static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_uw imm #endif /* Create imm by 1 inst. */ - tmp = get_immediate(imm); + tmp = get_imm(imm); if (tmp) { EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, reg, SLJIT_UNUSED, tmp)); return SLJIT_SUCCESS; } - tmp = get_immediate(~imm); + tmp = get_imm(~imm); if (tmp) { EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MVN_DP, 0, reg, SLJIT_UNUSED, tmp)); return SLJIT_SUCCESS; @@ -1342,20 +1343,36 @@ static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_uw imm #endif } +/* Helper function. Dst should be reg + value, using at most 1 instruction, flags does not set. */ +static sljit_si emit_set_delta(struct sljit_compiler *compiler, sljit_si dst, sljit_si reg, sljit_sw value) +{ + if (value >= 0) { + value = get_imm(value); + if (value) + return push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, dst, reg, value)); + } + else { + value = get_imm(-value); + if (value) + return push_inst(compiler, EMIT_DATA_PROCESS_INS(SUB_DP, 0, dst, reg, value)); + } + return SLJIT_ERR_UNSUPPORTED; +} + /* Can perform an operation using at most 1 instruction. */ -static int getput_arg_fast(struct sljit_compiler *compiler, int inp_flags, int reg, int arg, sljit_w argw) +static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si inp_flags, sljit_si reg, sljit_si arg, sljit_sw argw) { sljit_uw imm; if (arg & SLJIT_IMM) { - imm = get_immediate(argw); + imm = get_imm(argw); if (imm) { if (inp_flags & ARG_TEST) return 1; EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, reg, SLJIT_UNUSED, imm)); return -1; } - imm = get_immediate(~argw); + imm = get_imm(~argw); if (imm) { if (inp_flags & ARG_TEST) return 1; @@ -1415,7 +1432,7 @@ static int getput_arg_fast(struct sljit_compiler *compiler, int inp_flags, int r /* See getput_arg below. Note: can_cache is called only for binary operators. Those operators always uses word arguments without write back. */ -static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw) +static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw) { /* Immediate caching is not supported as it would be an operation on constant arguments. */ if (arg & SLJIT_IMM) @@ -1463,11 +1480,12 @@ static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw) } /* Emit the necessary instructions. See can_cache above. */ -static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, int arg, sljit_w argw, int next_arg, sljit_w next_argw) +static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si inp_flags, sljit_si reg, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw) { - int tmp_r; - sljit_w max_delta; - sljit_w sign; + sljit_si tmp_r; + sljit_sw max_delta; + sljit_sw sign; + sljit_uw imm; if (arg & SLJIT_IMM) { SLJIT_ASSERT(inp_flags & LOAD_DATA); @@ -1481,8 +1499,9 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i if ((arg & 0xf) == SLJIT_UNUSED) { /* Write back is not used. */ - if ((compiler->cache_arg & SLJIT_IMM) && (((sljit_uw)argw - (sljit_uw)compiler->cache_argw) <= (sljit_uw)max_delta || ((sljit_uw)compiler->cache_argw - (sljit_uw)argw) <= (sljit_uw)max_delta)) { - if (((sljit_uw)argw - (sljit_uw)compiler->cache_argw) <= (sljit_uw)max_delta) { + imm = (sljit_uw)(argw - compiler->cache_argw); + if ((compiler->cache_arg & SLJIT_IMM) && (imm <= (sljit_uw)max_delta || imm >= (sljit_uw)-max_delta)) { + if (imm <= (sljit_uw)max_delta) { sign = 1; argw = argw - compiler->cache_argw; } @@ -1491,18 +1510,14 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i argw = compiler->cache_argw - argw; } - if (max_delta & 0xf00) { - EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, sign, 0, reg, TMP_REG3, argw)); - } - else { - EMIT_INSTRUCTION(EMIT_DATA_TRANSFER(inp_flags, sign, 0, reg, TMP_REG3, TYPE2_TRANSFER_IMM(argw))); - } + GETPUT_ARG_DATA_TRANSFER(sign, 0, reg, TMP_REG3, argw); return SLJIT_SUCCESS; } /* With write back, we can create some sophisticated loads, but it is hard to decide whether we should convert downward (0s) or upward (1s). */ - if ((next_arg & SLJIT_MEM) && ((sljit_uw)argw - (sljit_uw)next_argw <= (sljit_uw)max_delta || (sljit_uw)next_argw - (sljit_uw)argw <= (sljit_uw)max_delta)) { + imm = (sljit_uw)(argw - next_argw); + if ((next_arg & SLJIT_MEM) && (imm <= (sljit_uw)max_delta || imm >= (sljit_uw)-max_delta)) { SLJIT_ASSERT(inp_flags & LOAD_DATA); compiler->cache_arg = SLJIT_IMM; @@ -1515,29 +1530,6 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i return SLJIT_SUCCESS; } - /* Extended imm addressing for [reg+imm] format. */ - sign = (max_delta << 8) | 0xff; - if (!(arg & 0xf0) && argw <= sign && argw >= -sign) { - TEST_WRITE_BACK(); - if (argw >= 0) { - sign = 1; - } - else { - sign = 0; - argw = -argw; - } - - /* Optimization: add is 0x4, sub is 0x2. Sign is 1 for add and 0 for sub. */ - if (max_delta & 0xf00) - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP << sign, 0, tmp_r, arg & 0xf, SRC2_IMM | (argw >> 12) | 0xa00)); - else - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP << sign, 0, tmp_r, arg & 0xf, SRC2_IMM | (argw >> 8) | 0xc00)); - - argw &= max_delta; - GETPUT_ARG_DATA_TRANSFER(sign, inp_flags & WRITE_BACK, reg, tmp_r, argw); - return SLJIT_SUCCESS; - } - if (arg & 0xf0) { SLJIT_ASSERT((argw & 0x3) && !(max_delta & 0xf00)); if (inp_flags & WRITE_BACK) @@ -1547,17 +1539,33 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i return SLJIT_SUCCESS; } - if (compiler->cache_arg == arg && ((sljit_uw)argw - (sljit_uw)compiler->cache_argw) <= (sljit_uw)max_delta) { + imm = (sljit_uw)(argw - compiler->cache_argw); + if (compiler->cache_arg == arg && imm <= (sljit_uw)max_delta) { SLJIT_ASSERT(!(inp_flags & WRITE_BACK)); - argw = argw - compiler->cache_argw; - GETPUT_ARG_DATA_TRANSFER(1, 0, reg, TMP_REG3, argw); + GETPUT_ARG_DATA_TRANSFER(1, 0, reg, TMP_REG3, imm); + return SLJIT_SUCCESS; + } + if (compiler->cache_arg == arg && imm >= (sljit_uw)-max_delta) { + SLJIT_ASSERT(!(inp_flags & WRITE_BACK)); + imm = (sljit_uw)-(sljit_sw)imm; + GETPUT_ARG_DATA_TRANSFER(0, 0, reg, TMP_REG3, imm); return SLJIT_SUCCESS; } - if (compiler->cache_arg == arg && ((sljit_uw)compiler->cache_argw - (sljit_uw)argw) <= (sljit_uw)max_delta) { - SLJIT_ASSERT(!(inp_flags & WRITE_BACK)); - argw = compiler->cache_argw - argw; - GETPUT_ARG_DATA_TRANSFER(0, 0, reg, TMP_REG3, argw); + imm = get_imm(argw & ~max_delta); + if (imm) { + TEST_WRITE_BACK(); + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, tmp_r, arg & 0xf, imm)); + GETPUT_ARG_DATA_TRANSFER(1, inp_flags & WRITE_BACK, reg, tmp_r, argw & max_delta); + return SLJIT_SUCCESS; + } + + imm = get_imm(-argw & ~max_delta); + if (imm) { + argw = -argw; + TEST_WRITE_BACK(); + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP, 0, tmp_r, arg & 0xf, imm)); + GETPUT_ARG_DATA_TRANSFER(0, inp_flags & WRITE_BACK, reg, tmp_r, argw & max_delta); return SLJIT_SUCCESS; } @@ -1579,7 +1587,8 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i return SLJIT_SUCCESS; } - if (arg == next_arg && !(inp_flags & WRITE_BACK) && ((sljit_uw)argw - (sljit_uw)next_argw <= (sljit_uw)max_delta || (sljit_uw)next_argw - (sljit_uw)argw <= (sljit_uw)max_delta)) { + imm = (sljit_uw)(argw - next_argw); + if (arg == next_arg && !(inp_flags & WRITE_BACK) && (imm <= (sljit_uw)max_delta || imm >= (sljit_uw)-max_delta)) { SLJIT_ASSERT(inp_flags & LOAD_DATA); FAIL_IF(load_immediate(compiler, TMP_REG3, argw)); EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG3, TMP_REG3, reg_map[arg & 0xf])); @@ -1602,10 +1611,26 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i return SLJIT_SUCCESS; } -static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw) +{ + if (getput_arg_fast(compiler, flags, reg, arg, argw)) + return compiler->error; + compiler->cache_arg = 0; + compiler->cache_argw = 0; + return getput_arg(compiler, flags, reg, arg, argw, 0, 0); +} + +static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w) +{ + if (getput_arg_fast(compiler, flags, reg, arg1, arg1w)) + return compiler->error; + return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w); +} + +static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si inp_flags, + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { /* arg1 goes to TMP_REG1 or src reg arg2 goes to TMP_REG2, imm or src reg @@ -1613,27 +1638,27 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */ /* We prefers register and simple consts. */ - int dst_r; - int src1_r; - int src2_r = 0; - int sugg_src2_r = TMP_REG2; - int flags = GET_FLAGS(op) ? SET_FLAGS : 0; + sljit_si dst_r; + sljit_si src1_r; + sljit_si src2_r = 0; + sljit_si sugg_src2_r = TMP_REG2; + sljit_si flags = GET_FLAGS(op) ? SET_FLAGS : 0; compiler->cache_arg = 0; compiler->cache_argw = 0; /* Destination check. */ - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REG3) { + if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) { + if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM)) + return SLJIT_SUCCESS; + dst_r = TMP_REG2; + } + else if (dst <= TMP_REG3) { dst_r = dst; flags |= REG_DEST; if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) sugg_src2_r = dst_r; } - else if (dst == SLJIT_UNUSED) { - if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM)) - return SLJIT_SUCCESS; - dst_r = TMP_REG2; - } else { SLJIT_ASSERT(dst & SLJIT_MEM); if (getput_arg_fast(compiler, inp_flags | ARG_TEST, TMP_REG2, dst, dstw)) { @@ -1647,9 +1672,9 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, } /* Source 1. */ - if (src1 >= SLJIT_TEMPORARY_REG1 && src1 <= TMP_REG3) + if (src1 <= TMP_REG3) src1_r = src1; - else if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= TMP_REG3) { + else if (src2 <= TMP_REG3) { flags |= ARGS_SWAPPED; src1_r = src2; src2 = src1; @@ -1659,7 +1684,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, src1_r = 0; if ((inp_flags & ALLOW_ANY_IMM) && (src1 & SLJIT_IMM)) { /* The second check will generate a hit. */ - src2_r = get_immediate(src1w); + src2_r = get_imm(src1w); if (src2_r) { flags |= ARGS_SWAPPED; src1 = src2; @@ -1667,7 +1692,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, break; } if (inp_flags & ALLOW_INV_IMM) { - src2_r = get_immediate(~src1w); + src2_r = get_imm(~src1w); if (src2_r) { flags |= ARGS_SWAPPED | INV_IMM; src1 = src2; @@ -1676,7 +1701,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, } } if (GET_OPCODE(op) == SLJIT_ADD) { - src2_r = get_immediate(-src1w); + src2_r = get_imm(-src1w); if (src2_r) { /* Note: ARGS_SWAPPED is intentionally not applied! */ src1 = src2; @@ -1695,7 +1720,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, /* Source 2. */ if (src2_r == 0) { - if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= TMP_REG3) { + if (src2 <= TMP_REG3) { src2_r = src2; flags |= REG_SOURCE; if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) @@ -1703,18 +1728,18 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, } else do { /* do { } while(0) is used because of breaks. */ if ((inp_flags & ALLOW_ANY_IMM) && (src2 & SLJIT_IMM)) { - src2_r = get_immediate(src2w); + src2_r = get_imm(src2w); if (src2_r) break; if (inp_flags & ALLOW_INV_IMM) { - src2_r = get_immediate(~src2w); + src2_r = get_imm(~src2w); if (src2_r) { flags |= INV_IMM; break; } } if (GET_OPCODE(op) == SLJIT_ADD) { - src2_r = get_immediate(-src2w); + src2_r = get_imm(-src2w); if (src2_r) { op = SLJIT_SUB | GET_ALL_FLAGS(op); flags &= ~ARGS_SWAPPED; @@ -1722,7 +1747,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, } } if (GET_OPCODE(op) == SLJIT_SUB && !(flags & ARGS_SWAPPED)) { - src2_r = get_immediate(-src2w); + src2_r = get_imm(-src2w); if (src2_r) { op = SLJIT_ADD | GET_ALL_FLAGS(op); flags &= ~ARGS_SWAPPED; @@ -1797,8 +1822,8 @@ extern "C" { #endif #if defined(__GNUC__) -extern unsigned int __aeabi_uidivmod(unsigned numerator, unsigned denominator); -extern unsigned int __aeabi_idivmod(unsigned numerator, unsigned denominator); +extern unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator); +extern int __aeabi_idivmod(int numerator, int denominator); #else #error "Software divmod functions are needed" #endif @@ -1807,7 +1832,7 @@ extern unsigned int __aeabi_idivmod(unsigned numerator, unsigned denominator); } #endif -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) { CHECK_ERROR(); check_sljit_emit_op0(compiler, op); @@ -1824,21 +1849,21 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int case SLJIT_SMUL: #if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) return push_inst(compiler, (op == SLJIT_UMUL ? UMULL : SMULL) - | (reg_map[SLJIT_TEMPORARY_REG2] << 16) - | (reg_map[SLJIT_TEMPORARY_REG1] << 12) - | (reg_map[SLJIT_TEMPORARY_REG1] << 8) - | reg_map[SLJIT_TEMPORARY_REG2]); + | (reg_map[SLJIT_SCRATCH_REG2] << 16) + | (reg_map[SLJIT_SCRATCH_REG1] << 12) + | (reg_map[SLJIT_SCRATCH_REG1] << 8) + | reg_map[SLJIT_SCRATCH_REG2]); #else - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, RM(SLJIT_TEMPORARY_REG2))); + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, RM(SLJIT_SCRATCH_REG2))); return push_inst(compiler, (op == SLJIT_UMUL ? UMULL : SMULL) - | (reg_map[SLJIT_TEMPORARY_REG2] << 16) - | (reg_map[SLJIT_TEMPORARY_REG1] << 12) - | (reg_map[SLJIT_TEMPORARY_REG1] << 8) + | (reg_map[SLJIT_SCRATCH_REG2] << 16) + | (reg_map[SLJIT_SCRATCH_REG1] << 12) + | (reg_map[SLJIT_SCRATCH_REG1] << 8) | reg_map[TMP_REG1]); #endif case SLJIT_UDIV: case SLJIT_SDIV: - if (compiler->temporaries >= 3) + if (compiler->scratches >= 3) EMIT_INSTRUCTION(0xe52d2008 /* str r2, [sp, #-8]! */); #if defined(__GNUC__) FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, @@ -1846,7 +1871,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int #else #error "Software divmod functions are needed" #endif - if (compiler->temporaries >= 3) + if (compiler->scratches >= 3) return push_inst(compiler, 0xe49d2008 /* ldr r2, [sp], #8 */); return SLJIT_SUCCESS; } @@ -1854,9 +1879,9 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +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); @@ -1867,36 +1892,38 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int case SLJIT_MOV: case SLJIT_MOV_UI: case SLJIT_MOV_SI: + case SLJIT_MOV_P: return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_MOV_UB: - return emit_op(compiler, SLJIT_MOV_UB, ALLOW_ANY_IMM | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_UB, ALLOW_ANY_IMM | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw); case SLJIT_MOV_SB: - return emit_op(compiler, SLJIT_MOV_SB, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_SB, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw); case SLJIT_MOV_UH: - return emit_op(compiler, SLJIT_MOV_UH, ALLOW_ANY_IMM | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_UH, ALLOW_ANY_IMM | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw); case SLJIT_MOV_SH: - return emit_op(compiler, SLJIT_MOV_SH, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_SH, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw); case SLJIT_MOVU: case SLJIT_MOVU_UI: case SLJIT_MOVU_SI: + case SLJIT_MOVU_P: return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_MOVU_UB: - return emit_op(compiler, SLJIT_MOV_UB, ALLOW_ANY_IMM | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_UB, ALLOW_ANY_IMM | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw); case SLJIT_MOVU_SB: - return emit_op(compiler, SLJIT_MOV_SB, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_SB, ALLOW_ANY_IMM | SIGNED_DATA | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw); case SLJIT_MOVU_UH: - return emit_op(compiler, SLJIT_MOV_UH, ALLOW_ANY_IMM | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_UH, ALLOW_ANY_IMM | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw); case SLJIT_MOVU_SH: - return emit_op(compiler, SLJIT_MOV_SH, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_SH, ALLOW_ANY_IMM | SIGNED_DATA | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw); case SLJIT_NOT: return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw); @@ -1914,10 +1941,10 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +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); @@ -1956,14 +1983,20 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg) { check_sljit_get_register_index(reg); return reg_map[reg]; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, int size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg) +{ + check_sljit_get_float_register_index(reg); + return reg; +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, + void *instruction, sljit_si size) { CHECK_ERROR(); check_sljit_emit_op_custom(compiler, instruction, size); @@ -1980,9 +2013,9 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compile /* 0 - no fpu 1 - vfp */ -static int arm_fpu_type = -1; +static sljit_si arm_fpu_type = -1; -static void init_compiler() +static void init_compiler(void) { if (arm_fpu_type != -1) return; @@ -1991,7 +2024,7 @@ static void init_compiler() arm_fpu_type = 1; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void) { if (arm_fpu_type == -1) init_compiler(); @@ -2002,7 +2035,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) #define arm_fpu_type 1 -SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void) { /* Always available. */ return 1; @@ -2010,56 +2043,61 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) #endif -#define EMIT_FPU_DATA_TRANSFER(add, load, base, freg, offs) \ - (VSTR | ((add) << 23) | ((load) << 20) | (reg_map[base] << 16) | (freg << 12) | (offs)) -#define EMIT_FPU_OPERATION(opcode, dst, src1, src2) \ - ((opcode) | ((dst) << 12) | (src1) | ((src2) << 16)) +#define FPU_LOAD (1 << 20) +#define EMIT_FPU_DATA_TRANSFER(inst, add, base, freg, offs) \ + ((inst) | ((add) << 23) | (reg_map[base] << 16) | (freg << 12) | (offs)) +#define EMIT_FPU_OPERATION(opcode, mode, dst, src1, src2) \ + ((opcode) | (mode) | ((dst) << 12) | (src1) | ((src2) << 16)) -static int emit_fpu_data_transfer(struct sljit_compiler *compiler, int fpu_reg, int load, int arg, sljit_w argw) +static sljit_si emit_fop_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg, sljit_sw argw) { + sljit_sw tmp; + sljit_uw imm; + sljit_sw inst = VSTR_F32 | (flags & (SLJIT_SINGLE_OP | FPU_LOAD)); SLJIT_ASSERT(arg & SLJIT_MEM); - /* Fast loads and stores. */ - if ((arg & 0xf) && !(arg & 0xf0) && (argw & 0x3) == 0) { - if (argw >= 0 && argw <= 0x3ff) { - EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, arg & 0xf, fpu_reg, argw >> 2)); - return SLJIT_SUCCESS; - } - if (argw < 0 && argw >= -0x3ff) { - EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(0, load, arg & 0xf, fpu_reg, (-argw) >> 2)); - return SLJIT_SUCCESS; - } - if (argw >= 0 && argw <= 0x3ffff) { - SLJIT_ASSERT(get_immediate(argw & 0x3fc00)); - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG1, arg & 0xf, get_immediate(argw & 0x3fc00))); - argw &= 0x3ff; - EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, TMP_REG1, fpu_reg, argw >> 2)); - return SLJIT_SUCCESS; - } - if (argw < 0 && argw >= -0x3ffff) { - argw = -argw; - SLJIT_ASSERT(get_immediate(argw & 0x3fc00)); - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP, 0, TMP_REG1, arg & 0xf, get_immediate(argw & 0x3fc00))); - argw &= 0x3ff; - EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(0, load, TMP_REG1, fpu_reg, argw >> 2)); - return SLJIT_SUCCESS; - } - } - - if (arg & 0xf0) { + if (SLJIT_UNLIKELY(arg & 0xf0)) { EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG1, arg & 0xf, RM((arg >> 4) & 0xf) | ((argw & 0x3) << 7))); - EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, TMP_REG1, fpu_reg, 0)); - return SLJIT_SUCCESS; + arg = SLJIT_MEM | TMP_REG1; + argw = 0; } - if (compiler->cache_arg == arg && ((argw - compiler->cache_argw) & 0x3) == 0) { - if (((sljit_uw)argw - (sljit_uw)compiler->cache_argw) <= 0x3ff) { - EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, TMP_REG3, fpu_reg, (argw - compiler->cache_argw) >> 2)); - return SLJIT_SUCCESS; + /* Fast loads and stores. */ + if ((arg & 0xf)) { + if (!(argw & ~0x3fc)) + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, arg & 0xf, reg, argw >> 2)); + if (!(-argw & ~0x3fc)) + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, arg & 0xf, reg, (-argw) >> 2)); + } + + if (compiler->cache_arg == arg) { + tmp = argw - compiler->cache_argw; + if (!(tmp & ~0x3fc)) + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG3, reg, tmp >> 2)); + if (!(-tmp & ~0x3fc)) + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG3, reg, -tmp >> 2)); + if (emit_set_delta(compiler, TMP_REG3, TMP_REG3, tmp) != SLJIT_ERR_UNSUPPORTED) { + FAIL_IF(compiler->error); + compiler->cache_argw = argw; + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG3, reg, 0)); } - if (((sljit_uw)compiler->cache_argw - (sljit_uw)argw) <= 0x3ff) { - EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(0, load, TMP_REG3, fpu_reg, (compiler->cache_argw - argw) >> 2)); - return SLJIT_SUCCESS; + } + + if (arg & 0xf) { + if (emit_set_delta(compiler, TMP_REG1, arg & 0xf, argw) != SLJIT_ERR_UNSUPPORTED) { + FAIL_IF(compiler->error); + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, 0)); + } + imm = get_imm(argw & ~0x3fc); + if (imm) { + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG1, arg & 0xf, imm)); + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG1, reg, (argw & 0x3fc) >> 2)); + } + imm = get_imm(-argw & ~0x3fc); + if (imm) { + argw = -argw; + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(SUB_DP, 0, TMP_REG1, arg & 0xf, imm)); + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG1, reg, (argw & 0x3fc) >> 2)); } } @@ -2072,142 +2110,154 @@ static int emit_fpu_data_transfer(struct sljit_compiler *compiler, int fpu_reg, else FAIL_IF(load_immediate(compiler, TMP_REG3, argw)); - EMIT_INSTRUCTION(EMIT_FPU_DATA_TRANSFER(1, load, TMP_REG3, fpu_reg, 0)); - return SLJIT_SUCCESS; + return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG3, reg, 0)); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - int dst_freg; + sljit_si dst_fr; CHECK_ERROR(); check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw); + SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100), float_transfer_bit_error); compiler->cache_arg = 0; compiler->cache_argw = 0; + op ^= SLJIT_SINGLE_OP; - if (GET_OPCODE(op) == SLJIT_FCMP) { - if (dst > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 1, dst, dstw)); + if (GET_OPCODE(op) == SLJIT_CMPD) { + if (dst > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, dst, dstw)); dst = TMP_FREG1; } - if (src > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG2, 1, src, srcw)); + if (src > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG2, src, srcw)); src = TMP_FREG2; } - EMIT_INSTRUCTION(VCMP_F64 | (dst << 12) | src); + EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VCMP_F32, op & SLJIT_SINGLE_OP, dst, src, 0)); EMIT_INSTRUCTION(VMRS); return SLJIT_SUCCESS; } - dst_freg = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG1 : dst; + dst_fr = (dst > SLJIT_FLOAT_REG6) ? TMP_FREG1 : dst; - if (src > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, dst_freg, 1, src, srcw)); - src = dst_freg; + if (src > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, dst_fr, src, srcw)); + src = dst_fr; } - switch (op) { - case SLJIT_FMOV: - if (src != dst_freg && dst_freg != TMP_FREG1) - EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMOV_F64, dst_freg, src, 0)); + switch (GET_OPCODE(op)) { + case SLJIT_MOVD: + if (src != dst_fr && dst_fr != TMP_FREG1) + EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMOV_F32, op & SLJIT_SINGLE_OP, dst_fr, src, 0)); break; - case SLJIT_FNEG: - EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VNEG_F64, dst_freg, src, 0)); + case SLJIT_NEGD: + EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VNEG_F32, op & SLJIT_SINGLE_OP, dst_fr, src, 0)); break; - case SLJIT_FABS: - EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VABS_F64, dst_freg, src, 0)); + case SLJIT_ABSD: + EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VABS_F32, op & SLJIT_SINGLE_OP, dst_fr, src, 0)); break; } - if (dst_freg == TMP_FREG1) - FAIL_IF(emit_fpu_data_transfer(compiler, src, 0, dst, dstw)); + if (dst_fr == TMP_FREG1) { + if (GET_OPCODE(op) == SLJIT_MOVD) + dst_fr = src; + FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), dst_fr, dst, dstw)); + } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(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) { - int dst_freg; + sljit_si dst_fr; CHECK_ERROR(); check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w); compiler->cache_arg = 0; compiler->cache_argw = 0; + op ^= SLJIT_SINGLE_OP; - dst_freg = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG1 : dst; + dst_fr = (dst > SLJIT_FLOAT_REG6) ? TMP_FREG1 : dst; - if (src2 > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG2, 1, src2, src2w)); + if (src2 > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG2, src2, src2w)); src2 = TMP_FREG2; } - if (src1 > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 1, src1, src1w)); + if (src1 > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP) | FPU_LOAD, TMP_FREG1, src1, src1w)); src1 = TMP_FREG1; } - switch (op) { - case SLJIT_FADD: - EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VADD_F64, dst_freg, src2, src1)); + switch (GET_OPCODE(op)) { + case SLJIT_ADDD: + EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VADD_F32, op & SLJIT_SINGLE_OP, dst_fr, src2, src1)); break; - case SLJIT_FSUB: - EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VSUB_F64, dst_freg, src2, src1)); + case SLJIT_SUBD: + EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VSUB_F32, op & SLJIT_SINGLE_OP, dst_fr, src2, src1)); break; - case SLJIT_FMUL: - EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMUL_F64, dst_freg, src2, src1)); + case SLJIT_MULD: + EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VMUL_F32, op & SLJIT_SINGLE_OP, dst_fr, src2, src1)); break; - case SLJIT_FDIV: - EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VDIV_F64, dst_freg, src2, src1)); + case SLJIT_DIVD: + EMIT_INSTRUCTION(EMIT_FPU_OPERATION(VDIV_F32, op & SLJIT_SINGLE_OP, dst_fr, src2, src1)); break; } - if (dst_freg == TMP_FREG1) - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 0, dst, dstw)); + if (dst_fr == TMP_FREG1) + FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_SINGLE_OP), TMP_FREG1, dst, dstw)); return SLJIT_SUCCESS; } +#undef FPU_LOAD +#undef EMIT_FPU_DATA_TRANSFER +#undef EMIT_FPU_OPERATION + /* --------------------------------------------------------------------- */ /* Other instructions */ /* --------------------------------------------------------------------- */ -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw) +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); ADJUST_LOCAL_OFFSET(dst, dstw); - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) - return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, RM(TMP_REG3))); - else if (dst & SLJIT_MEM) { - if (getput_arg_fast(compiler, WORD_DATA, TMP_REG3, dst, dstw)) - return compiler->error; - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG2, SLJIT_UNUSED, RM(TMP_REG3))); - compiler->cache_arg = 0; - compiler->cache_argw = 0; - return getput_arg(compiler, WORD_DATA, TMP_REG2, dst, dstw, 0, 0); - } + /* For UNUSED dst. Uncommon, but possible. */ + if (dst == SLJIT_UNUSED) + return SLJIT_SUCCESS; - return SLJIT_SUCCESS; + if (dst <= TMP_REG3) + return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst, SLJIT_UNUSED, RM(TMP_REG3))); + + /* Memory. */ + if (getput_arg_fast(compiler, WORD_DATA, TMP_REG3, dst, dstw)) + return compiler->error; + /* TMP_REG3 is used for caching. */ + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG2, SLJIT_UNUSED, RM(TMP_REG3))); + compiler->cache_arg = 0; + compiler->cache_argw = 0; + return getput_arg(compiler, WORD_DATA, TMP_REG2, dst, dstw, 0, 0); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw) +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); ADJUST_LOCAL_OFFSET(src, srcw); - if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) + if (src <= TMP_REG3) EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG3, SLJIT_UNUSED, RM(src))); else if (src & SLJIT_MEM) { if (getput_arg_fast(compiler, WORD_DATA | LOAD_DATA, TMP_REG3, src, srcw)) @@ -2228,7 +2278,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compi /* Conditional instructions */ /* --------------------------------------------------------------------- */ -static sljit_uw get_cc(int type) +static sljit_uw get_cc(sljit_si type) { switch (type) { case SLJIT_C_EQUAL: @@ -2270,11 +2320,11 @@ static sljit_uw get_cc(int type) return 0xd0000000; case SLJIT_C_OVERFLOW: - case SLJIT_C_FLOAT_NAN: + case SLJIT_C_FLOAT_UNORDERED: return 0x60000000; case SLJIT_C_NOT_OVERFLOW: - case SLJIT_C_FLOAT_NOT_NAN: + case SLJIT_C_FLOAT_ORDERED: return 0x70000000; default: /* SLJIT_JUMP */ @@ -2298,7 +2348,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi return label; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, int type) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type) { struct sljit_jump *jump; @@ -2339,7 +2389,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile return jump; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, int type, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw) { struct sljit_jump *jump; @@ -2367,60 +2417,74 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i jump->addr = compiler->size; } else { - if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) + if (src <= TMP_REG3) return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(src)); SLJIT_ASSERT(src & SLJIT_MEM); - FAIL_IF(emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, TMP_REG2, 0, TMP_REG1, 0, src, srcw)); + FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG2, src, srcw)); return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG2)); } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compiler, int op, int dst, sljit_w dstw, int type) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw, + sljit_si type) { - int reg; - sljit_uw cc; + sljit_si dst_r, flags = GET_ALL_FLAGS(op); + sljit_uw cc, ins; CHECK_ERROR(); - check_sljit_emit_cond_value(compiler, op, dst, dstw, type); + check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type); ADJUST_LOCAL_OFFSET(dst, dstw); + ADJUST_LOCAL_OFFSET(src, srcw); if (dst == SLJIT_UNUSED) return SLJIT_SUCCESS; + op = GET_OPCODE(op); cc = get_cc(type); - if (GET_OPCODE(op) == SLJIT_OR) { - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { - EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(ORR_DP, 0, dst, dst, SRC2_IMM | 1) & ~COND_MASK) | cc); - if (op & SLJIT_SET_E) - return push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, SET_FLAGS, TMP_REG1, SLJIT_UNUSED, RM(dst))); - return SLJIT_SUCCESS; - } + dst_r = (dst <= TMP_REG3) ? dst : TMP_REG2; - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, SRC2_IMM | 0)); - EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(MOV_DP, 0, TMP_REG1, SLJIT_UNUSED, SRC2_IMM | 1) & ~COND_MASK) | cc); -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) - compiler->skip_checks = 1; -#endif - return emit_op(compiler, op, ALLOW_IMM, dst, dstw, TMP_REG1, 0, dst, dstw); + if (op < SLJIT_ADD) { + EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst_r, SLJIT_UNUSED, SRC2_IMM | 0)); + EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(MOV_DP, 0, dst_r, SLJIT_UNUSED, SRC2_IMM | 1) & ~COND_MASK) | cc); + return (dst_r == TMP_REG2) ? emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw) : SLJIT_SUCCESS; } - reg = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2; + ins = (op == SLJIT_AND ? AND_DP : (op == SLJIT_OR ? ORR_DP : EOR_DP)); + if ((op == SLJIT_OR || op == SLJIT_XOR) && dst <= TMP_REG3 && dst == src) { + EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(ins, 0, dst, dst, SRC2_IMM | 1) & ~COND_MASK) | cc); + /* The condition must always be set, even if the ORR/EOR is not executed above. */ + return (flags & SLJIT_SET_E) ? push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, SET_FLAGS, TMP_REG1, SLJIT_UNUSED, RM(dst))) : SLJIT_SUCCESS; + } - EMIT_INSTRUCTION(EMIT_DATA_PROCESS_INS(MOV_DP, 0, reg, SLJIT_UNUSED, SRC2_IMM | 0)); - EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(MOV_DP, 0, reg, SLJIT_UNUSED, SRC2_IMM | 1) & ~COND_MASK) | cc); + compiler->cache_arg = 0; + compiler->cache_argw = 0; + if (src & SLJIT_MEM) { + FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw)); + src = TMP_REG1; + srcw = 0; + } else if (src & SLJIT_IMM) { + FAIL_IF(load_immediate(compiler, TMP_REG1, srcw)); + src = TMP_REG1; + srcw = 0; + } - if (reg == TMP_REG2) - return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, TMP_REG2, 0); - return SLJIT_SUCCESS; + EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(ins, 0, dst_r, src, SRC2_IMM | 1) & ~COND_MASK) | cc); + EMIT_INSTRUCTION((EMIT_DATA_PROCESS_INS(ins, 0, dst_r, src, SRC2_IMM | 0) & ~COND_MASK) | (cc ^ 0x10000000)); + if (dst_r == TMP_REG2) + FAIL_IF(emit_op_mem2(compiler, WORD_DATA, TMP_REG2, dst, dstw, 0, 0)); + + return (flags & SLJIT_SET_E) ? push_inst(compiler, EMIT_DATA_PROCESS_INS(MOV_DP, SET_FLAGS, TMP_REG1, SLJIT_UNUSED, RM(dst_r))) : SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w init_value) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value) { struct sljit_const *const_; - int reg; + sljit_si reg; CHECK_ERROR_PTR(); check_sljit_emit_const(compiler, dst, dstw, init_value); @@ -2429,7 +2493,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const)); PTR_FAIL_IF(!const_); - reg = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2; + reg = (dst <= TMP_REG3) ? dst : TMP_REG2; #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_DATA | LOAD_DATA, 1, 0, reg, TMP_PC, 0), init_value)); @@ -2440,8 +2504,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi set_const(const_, compiler); if (reg == TMP_REG2 && dst != SLJIT_UNUSED) - if (emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, TMP_REG2, 0)) - return NULL; + PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw)); return const_; } @@ -2450,7 +2513,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad inline_set_jump_addr(addr, new_addr, 1); } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant) { inline_set_const(addr, new_constant, 1); } diff --git a/src/3rd/pcre/sjconf.h b/src/3rd/pcre/sjconf.h index 32c3b10437..4f0fe4463a 100644 --- a/src/3rd/pcre/sjconf.h +++ b/src/3rd/pcre/sjconf.h @@ -47,6 +47,8 @@ /* #define SLJIT_CONFIG_PPC_32 1 */ /* #define SLJIT_CONFIG_PPC_64 1 */ /* #define SLJIT_CONFIG_MIPS_32 1 */ +/* #define SLJIT_CONFIG_SPARC_32 1 */ +/* #define SLJIT_CONFIG_TILEGX 1 */ /* #define SLJIT_CONFIG_AUTO 1 */ /* #define SLJIT_CONFIG_UNSUPPORTED 1 */ diff --git a/src/3rd/pcre/sjconfi.h b/src/3rd/pcre/sjconfi.h index dce5328110..6281066f62 100644 --- a/src/3rd/pcre/sjconfi.h +++ b/src/3rd/pcre/sjconfi.h @@ -33,18 +33,23 @@ Feature detection (boolean) macros: SLJIT_32BIT_ARCHITECTURE : 32 bit architecture SLJIT_64BIT_ARCHITECTURE : 64 bit architecture - SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_w/sljit_uw array by index - SLJIT_FLOAT_SHIFT : the shift required to apply when accessing a double array by index + SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index + SLJIT_DOUBLE_SHIFT : the shift required to apply when accessing a double array by index SLJIT_LITTLE_ENDIAN : little endian architecture SLJIT_BIG_ENDIAN : big endian architecture SLJIT_UNALIGNED : allows unaligned memory accesses for non-fpu operations (only!) SLJIT_INDIRECT_CALL : see SLJIT_FUNC_OFFSET() for more information + SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address Types and useful macros: - sljit_b, sljit_ub : signed and unsigned 8 bit byte - sljit_h, sljit_uh : signed and unsigned 16 bit half-word (short) type - sljit_i, sljit_ui : signed and unsigned 32 bit integer type - sljit_w, sljit_uw : signed and unsigned machine word, enough to store a pointer (same as intptr_t) + sljit_sb, sljit_ub : signed and unsigned 8 bit byte + sljit_sh, sljit_uh : signed and unsigned 16 bit half-word (short) type + sljit_si, sljit_ui : signed and unsigned 32 bit integer type + sljit_sw, sljit_uw : signed and unsigned machine word, enough to store a pointer + sljit_p : unsgined pointer value (usually the same as sljit_uw, but + some 64 bit ABIs may use 32 bit pointers) + sljit_s : single precision floating point value + sljit_d : double precision floating point value SLJIT_CALL : C calling convention define for both calling JIT form C and C callbacks for JIT SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (compiler independent helper) */ @@ -57,6 +62,8 @@ || (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \ || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \ + || (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \ + || (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \ || (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \ || (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)) #error "An architecture must be selected" @@ -70,7 +77,9 @@ + (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \ + (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \ + (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \ + + (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \ + (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \ + + (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \ + (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \ + (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2 #error "Multiple architectures are selected" @@ -93,12 +102,16 @@ #else #define SLJIT_CONFIG_ARM_V5 1 #endif -#elif defined(__ppc64__) || defined(__powerpc64__) +#elif defined(__ppc64__) || defined(__powerpc64__) || defined(_ARCH_PPC64) || (defined(_POWER) && defined(__64BIT__)) #define SLJIT_CONFIG_PPC_64 1 -#elif defined(__ppc__) || defined(__powerpc__) +#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER) #define SLJIT_CONFIG_PPC_32 1 -#elif defined(__mips__) +#elif defined(__mips__) && !defined(_LP64) #define SLJIT_CONFIG_MIPS_32 1 +#elif defined(__sparc__) || defined(__sparc) +#define SLJIT_CONFIG_SPARC_32 1 +#elif defined(__tilegx__) +#define SLJIT_CONFIG_TILEGX 1 #else /* Unsupported architecture */ #define SLJIT_CONFIG_UNSUPPORTED 1 @@ -164,9 +177,13 @@ #endif /* !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY) */ #ifndef SLJIT_INLINE -/* Inline functions. */ +/* Inline functions. Some old compilers do not support them. */ +#if defined(__SUNPRO_C) && __SUNPRO_C <= 0x510 +#define SLJIT_INLINE +#else #define SLJIT_INLINE __inline #endif +#endif /* !SLJIT_INLINE */ #ifndef SLJIT_CONST /* Const variables. */ @@ -208,12 +225,25 @@ #define SLJIT_CACHE_FLUSH(from, to) \ sys_icache_invalidate((char*)(from), (char*)(to) - (char*)(from)) +#elif defined __ANDROID__ + +/* Android lacks __clear_cache; instead, cacheflush should be used. */ + +#define SLJIT_CACHE_FLUSH(from, to) \ + cacheflush((long)(from), (long)(to), 0) + #elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) /* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */ #define SLJIT_CACHE_FLUSH(from, to) \ ppc_cache_flush((from), (to)) +#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) + +/* The __clear_cache() implementation of GCC is a dummy function on Sparc. */ +#define SLJIT_CACHE_FLUSH(from, to) \ + sparc_cache_flush((from), (to)) + #else /* Calls __ARM_NR_cacheflush on ARM-Linux. */ @@ -226,15 +256,15 @@ /* 8 bit byte type. */ typedef unsigned char sljit_ub; -typedef signed char sljit_b; +typedef signed char sljit_sb; /* 16 bit half-word type. */ typedef unsigned short int sljit_uh; -typedef signed short int sljit_h; +typedef signed short int sljit_sh; /* 32 bit integer type. */ typedef unsigned int sljit_ui; -typedef signed int sljit_i; +typedef signed int sljit_si; /* Machine word type. Can encapsulate a pointer. 32 bit for 32 bit machines. @@ -243,26 +273,37 @@ typedef signed int sljit_i; /* Just to have something. */ #define SLJIT_WORD_SHIFT 0 typedef unsigned long int sljit_uw; -typedef long int sljit_w; -#elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) +typedef long int sljit_sw; +#elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \ + && !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \ + && !(defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) #define SLJIT_32BIT_ARCHITECTURE 1 #define SLJIT_WORD_SHIFT 2 typedef unsigned int sljit_uw; -typedef int sljit_w; +typedef int sljit_sw; #else #define SLJIT_64BIT_ARCHITECTURE 1 #define SLJIT_WORD_SHIFT 3 #ifdef _WIN32 typedef unsigned __int64 sljit_uw; -typedef __int64 sljit_w; +typedef __int64 sljit_sw; #else typedef unsigned long int sljit_uw; -typedef long int sljit_w; +typedef long int sljit_sw; #endif #endif -/* Double precision. */ -#define SLJIT_FLOAT_SHIFT 3 +typedef sljit_uw sljit_p; + +/* Floating point types. */ +typedef float sljit_s; +typedef double sljit_d; + +/* Shift for pointer sized data. */ +#define SLJIT_POINTER_SHIFT SLJIT_WORD_SHIFT + +/* Shift for double precision sized data. */ +#define SLJIT_DOUBLE_SHIFT 3 #ifndef SLJIT_W @@ -280,7 +321,7 @@ typedef long int sljit_w; /* ABI (Application Binary Interface) types. */ #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__APPLE__) #if ( __GNUC__ > 3 ) || ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 4 ) ) #define SLJIT_CALL __attribute__ ((fastcall)) @@ -289,20 +330,24 @@ typedef long int sljit_w; #define SLJIT_CALL #endif -#elif defined(_WIN32) +#elif defined(_MSC_VER) -#ifdef __BORLANDC__ -#define SLJIT_CALL __msfastcall -#else /* __BORLANDC__ */ #define SLJIT_CALL __fastcall -#endif /* __BORLANDC__ */ #define SLJIT_X86_32_FASTCALL 1 -#else /* defined(_WIN32) */ -#define SLJIT_CALL __stdcall +#elif defined(__BORLANDC__) + +#define SLJIT_CALL __msfastcall +#define SLJIT_X86_32_FASTCALL 1 + +#else /* Unknown compiler. */ + +/* The cdecl attribute is the default. */ +#define SLJIT_CALL + #endif -#else /* Other architectures. */ +#else /* Non x86-32 architectures. */ #define SLJIT_CALL @@ -313,7 +358,9 @@ typedef long int sljit_w; #if !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN) /* These macros are useful for the application. */ -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) +#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \ + || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \ + || (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) #define SLJIT_BIG_ENDIAN 1 #elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) @@ -339,11 +386,21 @@ typedef long int sljit_w; #error "Exactly one endianness must be selected" #endif -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) -/* It seems ppc64 compilers use an indirect addressing for functions. - It makes things really complicated. */ +#ifndef SLJIT_INDIRECT_CALL +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32 && defined _AIX) +/* It seems certain ppc compilers use an indirect addressing for functions + which makes things complicated. */ #define SLJIT_INDIRECT_CALL 1 #endif +#endif /* SLJIT_INDIRECT_CALL */ + +#ifndef SLJIT_RETURN_ADDRESS_OFFSET +#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) +#define SLJIT_RETURN_ADDRESS_OFFSET 8 +#else +#define SLJIT_RETURN_ADDRESS_OFFSET 0 +#endif +#endif /* SLJIT_RETURN_ADDRESS_OFFSET */ #ifndef SLJIT_SSE2 @@ -377,21 +434,33 @@ typedef long int sljit_w; #if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size); SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr); +SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void); #define SLJIT_MALLOC_EXEC(size) sljit_malloc_exec(size) #define SLJIT_FREE_EXEC(ptr) sljit_free_exec(ptr) #endif -#if (defined SLJIT_DEBUG && SLJIT_DEBUG) || (defined SLJIT_VERBOSE && SLJIT_VERBOSE) +#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) #include #endif #if (defined SLJIT_DEBUG && SLJIT_DEBUG) -/* Feel free to redefine these two macros. */ -#ifndef SLJIT_ASSERT +#if !defined(SLJIT_ASSERT) || !defined(SLJIT_ASSERT_STOP) + +/* SLJIT_HALT_PROCESS must halt the process. */ +#ifndef SLJIT_HALT_PROCESS +#include #define SLJIT_HALT_PROCESS() \ - *((int*)0) = 0 + abort(); +#endif /* !SLJIT_HALT_PROCESS */ + +#include + +#endif /* !SLJIT_ASSERT || !SLJIT_ASSERT_STOP */ + +/* Feel free to redefine these two macros. */ +#ifndef SLJIT_ASSERT #define SLJIT_ASSERT(x) \ do { \ @@ -415,6 +484,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr); #else /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */ +/* Forcing empty, but valid statements. */ #undef SLJIT_ASSERT #undef SLJIT_ASSERT_STOP diff --git a/src/3rd/pcre/sjexeca.c b/src/3rd/pcre/sjexeca.c index f66744df82..f24ed33797 100644 --- a/src/3rd/pcre/sjexeca.c +++ b/src/3rd/pcre/sjexeca.c @@ -52,7 +52,7 @@ The unused blocks are stored in a chain list pointed by free_blocks. This list is useful if we need to find a suitable memory area when the allocator is called. - + When a block is freed, the new free block is connected to its adjacent free blocks if possible. @@ -83,7 +83,7 @@ static SLJIT_INLINE void* alloc_chunk(sljit_uw size) { - return VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); } static SLJIT_INLINE void free_chunk(void* chunk, sljit_uw size) @@ -94,11 +94,20 @@ static SLJIT_INLINE void free_chunk(void* chunk, sljit_uw size) #else -#include - static SLJIT_INLINE void* alloc_chunk(sljit_uw size) { - void* retval = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); + void* retval; + +#ifdef MAP_ANON + retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0); +#else + if (dev_zero < 0) { + if (open_dev_zero()) + return NULL; + } + retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, dev_zero, 0); +#endif + return (retval != MAP_FAILED) ? retval : NULL; } @@ -202,7 +211,10 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size) chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK; header = (struct block_header*)alloc_chunk(chunk_size); - PTR_FAIL_IF(!header); + if (!header) { + allocator_release_lock(); + return NULL; + } chunk_size -= sizeof(struct block_header); total_size += chunk_size; @@ -237,14 +249,14 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) struct free_block* free_block; allocator_grab_lock(); - header = AS_BLOCK_HEADER(ptr, -(sljit_w)sizeof(struct block_header)); + header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header)); allocated_size -= header->size; /* Connecting free blocks together if possible. */ /* If header->prev_size == 0, free_block will equal to header. In this case, free_block->header.size will be > 0. */ - free_block = AS_FREE_BLOCK(header, -(sljit_w)header->prev_size); + free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size); if (SLJIT_UNLIKELY(!free_block->header.size)) { free_block->size += header->size; header = AS_BLOCK_HEADER(free_block, free_block->size); @@ -275,3 +287,26 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr) allocator_release_lock(); } + +SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void) +{ + struct free_block* free_block; + struct free_block* next_free_block; + + allocator_grab_lock(); + + free_block = free_blocks; + while (free_block) { + next_free_block = free_block->next; + if (!free_block->header.prev_size && + AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) { + total_size -= free_block->size; + sljit_remove_free_block(free_block); + free_chunk(free_block, free_block->size + sizeof(struct block_header)); + } + free_block = next_free_block; + } + + SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks)); + allocator_release_lock(); +} diff --git a/src/3rd/pcre/sjlir.c b/src/3rd/pcre/sjlir.c index 300b0ff913..59ed08ce5f 100644 --- a/src/3rd/pcre/sjlir.c +++ b/src/3rd/pcre/sjlir.c @@ -89,7 +89,10 @@ ((op) & (SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_O | SLJIT_SET_C)) #define GET_ALL_FLAGS(op) \ - ((op) & (SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS)) + ((op) & (SLJIT_INT_OP | SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS)) + +#define TYPE_CAST_NEEDED(op) \ + (((op) >= SLJIT_MOV_UB && (op) <= SLJIT_MOV_SH) || ((op) >= SLJIT_MOVU_UB && (op) <= SLJIT_MOVU_SH)) #define BUF_SIZE 4096 @@ -105,93 +108,135 @@ /* SLJIT_REWRITABLE_JUMP is 0x1000. */ #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - #define PATCH_MB 0x4 - #define PATCH_MW 0x8 +# define PATCH_MB 0x4 +# define PATCH_MW 0x8 #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - #define PATCH_MD 0x10 +# define PATCH_MD 0x10 #endif #endif #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - #define IS_BL 0x4 - #define PATCH_B 0x8 +# define IS_BL 0x4 +# define PATCH_B 0x8 #endif #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - #define CPOOL_SIZE 512 +# define CPOOL_SIZE 512 #endif #if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) - #define IS_CONDITIONAL 0x04 - #define IS_BL 0x08 +# define IS_COND 0x04 +# define IS_BL 0x08 /* cannot be encoded as branch */ - #define B_TYPE0 0x00 +# define B_TYPE0 0x00 /* conditional + imm8 */ - #define B_TYPE1 0x10 +# define B_TYPE1 0x10 /* conditional + imm20 */ - #define B_TYPE2 0x20 +# define B_TYPE2 0x20 /* IT + imm24 */ - #define B_TYPE3 0x30 +# define B_TYPE3 0x30 /* imm11 */ - #define B_TYPE4 0x40 +# define B_TYPE4 0x40 /* imm24 */ - #define B_TYPE5 0x50 +# define B_TYPE5 0x50 /* BL + imm24 */ - #define BL_TYPE6 0x60 +# define BL_TYPE6 0x60 /* 0xf00 cc code for branches */ #endif #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - #define UNCOND_B 0x04 - #define PATCH_B 0x08 - #define ABSOLUTE_B 0x10 +# define UNCOND_B 0x04 +# define PATCH_B 0x08 +# define ABSOLUTE_B 0x10 #endif #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - #define IS_MOVABLE 0x04 - #define IS_JAL 0x08 - #define IS_BIT26_COND 0x10 - #define IS_BIT16_COND 0x20 +# define IS_MOVABLE 0x04 +# define IS_JAL 0x08 +# define IS_BIT26_COND 0x10 +# define IS_BIT16_COND 0x20 - #define IS_COND (IS_BIT26_COND | IS_BIT16_COND) +# define IS_COND (IS_BIT26_COND | IS_BIT16_COND) - #define PATCH_B 0x40 - #define PATCH_J 0x80 +# define PATCH_B 0x40 +# define PATCH_J 0x80 /* instruction types */ - #define UNMOVABLE_INS 0 +# define MOVABLE_INS 0 /* 1 - 31 last destination register */ - #define FCSR_FCC 32 /* no destination (i.e: store) */ - #define MOVABLE_INS 33 +# define UNMOVABLE_INS 32 + /* FPU status register */ +# define FCSR_FCC 33 +#endif + +#if (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) +# define IS_JAL 0x04 +# define IS_COND 0x08 + +# define PATCH_B 0x10 +# define PATCH_J 0x20 +#endif + +#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) +# define IS_MOVABLE 0x04 +# define IS_COND 0x08 +# define IS_CALL 0x10 + +# define PATCH_B 0x20 +# define PATCH_CALL 0x40 + + /* instruction types */ +# define MOVABLE_INS 0 + /* 1 - 31 last destination register */ + /* no destination (i.e: store) */ +# define UNMOVABLE_INS 32 + +# define DST_INS_MASK 0xff + + /* ICC_SET is the same as SET_FLAGS. */ +# define ICC_IS_SET (1 << 23) +# define FCC_IS_SET (1 << 24) #endif #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) #define SLJIT_HAS_VARIABLE_LOCALS_OFFSET 1 +#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) +#define FIXED_LOCALS_OFFSET (3 * sizeof(sljit_sw)) +#endif #endif #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) #define SLJIT_HAS_FIXED_LOCALS_OFFSET 1 #ifdef _WIN64 -#define FIXED_LOCALS_OFFSET (4 * sizeof(sljit_w)) +#define FIXED_LOCALS_OFFSET ((4 + 2) * sizeof(sljit_sw)) #else -#define FIXED_LOCALS_OFFSET (sizeof(sljit_w)) +#define FIXED_LOCALS_OFFSET (sizeof(sljit_sw)) #endif #endif -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#define SLJIT_HAS_FIXED_LOCALS_OFFSET 1 -#define FIXED_LOCALS_OFFSET (4 * sizeof(sljit_w)) -#endif - #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) #define SLJIT_HAS_FIXED_LOCALS_OFFSET 1 -#define FIXED_LOCALS_OFFSET (2 * sizeof(sljit_w)) +#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) +#define FIXED_LOCALS_OFFSET ((6 + 8) * sizeof(sljit_sw)) +#else +#define FIXED_LOCALS_OFFSET (2 * sizeof(sljit_sw)) +#endif #endif #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) #define SLJIT_HAS_FIXED_LOCALS_OFFSET 1 -#define FIXED_LOCALS_OFFSET ((7 + 8) * sizeof(sljit_w)) +#define FIXED_LOCALS_OFFSET ((6 + 8) * sizeof(sljit_sw)) +#endif + +#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) +#define SLJIT_HAS_FIXED_LOCALS_OFFSET 1 +#define FIXED_LOCALS_OFFSET (4 * sizeof(sljit_sw)) +#endif + +#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) +#define SLJIT_HAS_FIXED_LOCALS_OFFSET 1 +#define FIXED_LOCALS_OFFSET (23 * sizeof(sljit_sw)) #endif #if (defined SLJIT_HAS_VARIABLE_LOCALS_OFFSET && SLJIT_HAS_VARIABLE_LOCALS_OFFSET) @@ -233,7 +278,7 @@ #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || ((defined SLJIT_SSE2 && SLJIT_SSE2) && ((defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64))) #define SLJIT_NEEDS_COMPILER_INIT 1 -static int compiler_initialized = 0; +static sljit_si compiler_initialized = 0; /* A thread safe initialization. */ static void init_compiler(void); #endif @@ -246,11 +291,18 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void) SLJIT_ZEROMEM(compiler, sizeof(struct sljit_compiler)); SLJIT_COMPILE_ASSERT( - sizeof(sljit_b) == 1 && sizeof(sljit_ub) == 1 - && sizeof(sljit_h) == 2 && sizeof(sljit_uh) == 2 - && sizeof(sljit_i) == 4 && sizeof(sljit_ui) == 4 - && ((sizeof(sljit_w) == 4 && sizeof(sljit_uw) == 4) || (sizeof(sljit_w) == 8 && sizeof(sljit_uw) == 8)), + sizeof(sljit_sb) == 1 && sizeof(sljit_ub) == 1 + && sizeof(sljit_sh) == 2 && sizeof(sljit_uh) == 2 + && sizeof(sljit_si) == 4 && sizeof(sljit_ui) == 4 + && (sizeof(sljit_p) == 4 || sizeof(sljit_p) == 8) + && sizeof(sljit_p) <= sizeof(sljit_sw) + && (sizeof(sljit_sw) == 4 || sizeof(sljit_sw) == 8) + && (sizeof(sljit_uw) == 4 || sizeof(sljit_uw) == 8), invalid_integer_types); + SLJIT_COMPILE_ASSERT(SLJIT_INT_OP == SLJIT_SINGLE_OP, + int_op_and_single_op_must_be_the_same); + SLJIT_COMPILE_ASSERT(SLJIT_REWRITABLE_JUMP != SLJIT_SINGLE_OP, + rewritable_jump_and_single_op_must_not_be_the_same); /* Only the non-zero members must be set. */ compiler->error = SLJIT_SUCCESS; @@ -272,7 +324,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void) compiler->abuf->next = NULL; compiler->abuf->used_size = 0; - compiler->temporaries = -1; + compiler->scratches = -1; compiler->saveds = -1; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) @@ -295,6 +347,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void) compiler->delay_slot = UNMOVABLE_INS; #endif +#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) + compiler->delay_slot = UNMOVABLE_INS; +#endif + #if (defined SLJIT_NEEDS_COMPILER_INIT && SLJIT_NEEDS_COMPILER_INIT) if (!compiler_initialized) { init_compiler(); @@ -336,7 +392,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code) /* Remove thumb mode flag. */ SLJIT_FREE_EXEC((void*)((sljit_uw)code & ~0x1)); } -#elif (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) +#elif (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code) { /* Resolve indirection. */ @@ -374,12 +430,13 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw /* Private functions */ /* --------------------------------------------------------------------- */ -static void* ensure_buf(struct sljit_compiler *compiler, int size) +static void* ensure_buf(struct sljit_compiler *compiler, sljit_uw size) { sljit_ub *ret; struct sljit_memory_fragment *new_frag; - if (compiler->buf->used_size + size <= (int)(BUF_SIZE - sizeof(sljit_uw) - sizeof(void*))) { + SLJIT_ASSERT(size <= 256); + if (compiler->buf->used_size + size <= (BUF_SIZE - (sljit_uw)SLJIT_OFFSETOF(struct sljit_memory_fragment, memory))) { ret = compiler->buf->memory + compiler->buf->used_size; compiler->buf->used_size += size; return ret; @@ -392,12 +449,13 @@ static void* ensure_buf(struct sljit_compiler *compiler, int size) return new_frag->memory; } -static void* ensure_abuf(struct sljit_compiler *compiler, int size) +static void* ensure_abuf(struct sljit_compiler *compiler, sljit_uw size) { sljit_ub *ret; struct sljit_memory_fragment *new_frag; - if (compiler->abuf->used_size + size <= (int)(ABUF_SIZE - sizeof(sljit_uw) - sizeof(void*))) { + SLJIT_ASSERT(size <= 256); + if (compiler->abuf->used_size + size <= (ABUF_SIZE - (sljit_uw)SLJIT_OFFSETOF(struct sljit_memory_fragment, memory))) { ret = compiler->abuf->memory + compiler->abuf->used_size; compiler->abuf->used_size += size; return ret; @@ -410,7 +468,7 @@ static void* ensure_abuf(struct sljit_compiler *compiler, int size) return new_frag->memory; } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, int size) +SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_si size) { CHECK_ERROR_PTR(); @@ -453,7 +511,7 @@ static SLJIT_INLINE void set_label(struct sljit_label *label, struct sljit_compi compiler->last_label = label; } -static SLJIT_INLINE void set_jump(struct sljit_jump *jump, struct sljit_compiler *compiler, int flags) +static SLJIT_INLINE void set_jump(struct sljit_jump *jump, struct sljit_compiler *compiler, sljit_si flags) { jump->next = NULL; jump->flags = flags; @@ -498,8 +556,8 @@ static SLJIT_INLINE void set_const(struct sljit_const *const_, struct sljit_comp case SLJIT_MUL: \ SLJIT_ASSERT(!(op & (SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_C))); \ break; \ - case SLJIT_FCMP: \ - SLJIT_ASSERT(!(op & (SLJIT_INT_OP | SLJIT_SET_U | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))); \ + case SLJIT_CMPD: \ + SLJIT_ASSERT(!(op & (SLJIT_SET_U | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))); \ SLJIT_ASSERT((op & (SLJIT_SET_E | SLJIT_SET_S))); \ break; \ case SLJIT_ADD: \ @@ -511,19 +569,30 @@ static SLJIT_INLINE void set_const(struct sljit_const *const_, struct sljit_comp case SLJIT_SUBC: \ SLJIT_ASSERT(!(op & (SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_O))); \ break; \ - default: \ + case SLJIT_BREAKPOINT: \ + case SLJIT_NOP: \ + case SLJIT_UMUL: \ + case SLJIT_SMUL: \ + case SLJIT_MOV: \ + case SLJIT_MOV_P: \ + case SLJIT_MOVU: \ + case SLJIT_MOVU_P: \ /* Nothing allowed */ \ SLJIT_ASSERT(!(op & (SLJIT_INT_OP | SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))); \ break; \ + default: \ + /* Only SLJIT_INT_OP or SLJIT_SINGLE_OP is allowed. */ \ + SLJIT_ASSERT(!(op & (SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_O | SLJIT_SET_C | SLJIT_KEEP_FLAGS))); \ + break; \ } #define FUNCTION_CHECK_IS_REG(r) \ ((r) == SLJIT_UNUSED || \ - ((r) >= SLJIT_TEMPORARY_REG1 && (r) <= SLJIT_TEMPORARY_REG1 - 1 + compiler->temporaries) || \ + ((r) >= SLJIT_SCRATCH_REG1 && (r) <= SLJIT_SCRATCH_REG1 - 1 + compiler->scratches) || \ ((r) >= SLJIT_SAVED_REG1 && (r) <= SLJIT_SAVED_REG1 - 1 + compiler->saveds)) #define FUNCTION_CHECK_SRC(p, i) \ - SLJIT_ASSERT(compiler->temporaries != -1 && compiler->saveds != -1); \ + SLJIT_ASSERT(compiler->scratches != -1 && compiler->saveds != -1); \ if (FUNCTION_CHECK_IS_REG(p)) \ SLJIT_ASSERT((i) == 0 && (p) != SLJIT_UNUSED); \ else if ((p) == SLJIT_IMM) \ @@ -542,7 +611,7 @@ static SLJIT_INLINE void set_const(struct sljit_const *const_, struct sljit_comp SLJIT_ASSERT_STOP(); #define FUNCTION_CHECK_DST(p, i) \ - SLJIT_ASSERT(compiler->temporaries != -1 && compiler->saveds != -1); \ + SLJIT_ASSERT(compiler->scratches != -1 && compiler->saveds != -1); \ if (FUNCTION_CHECK_IS_REG(p)) \ SLJIT_ASSERT((i) == 0); \ else if ((p) == (SLJIT_MEM1(SLJIT_LOCALS_REG))) \ @@ -559,7 +628,7 @@ static SLJIT_INLINE void set_const(struct sljit_const *const_, struct sljit_comp SLJIT_ASSERT_STOP(); #define FUNCTION_FCHECK(p, i) \ - if ((p) >= SLJIT_FLOAT_REG1 && (p) <= SLJIT_FLOAT_REG4) \ + if ((p) >= SLJIT_FLOAT_REG1 && (p) <= SLJIT_FLOAT_REG6) \ SLJIT_ASSERT(i == 0); \ else if ((p) & SLJIT_MEM) { \ SLJIT_ASSERT(FUNCTION_CHECK_IS_REG((p) & 0xf)); \ @@ -574,10 +643,7 @@ static SLJIT_INLINE void set_const(struct sljit_const *const_, struct sljit_comp SLJIT_ASSERT_STOP(); #define FUNCTION_CHECK_OP1() \ - if (GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOVU_SI) { \ - SLJIT_ASSERT(!GET_ALL_FLAGS(op)); \ - } \ - if (GET_OPCODE(op) >= SLJIT_MOVU && GET_OPCODE(op) <= SLJIT_MOVU_SI) { \ + if (GET_OPCODE(op) >= SLJIT_MOVU && GET_OPCODE(op) <= SLJIT_MOVU_P) { \ SLJIT_ASSERT(!(src & SLJIT_MEM) || (src & 0xf) != SLJIT_LOCALS_REG); \ SLJIT_ASSERT(!(dst & SLJIT_MEM) || (dst & 0xf) != SLJIT_LOCALS_REG); \ if ((src & SLJIT_MEM) && (src & 0xf)) \ @@ -594,23 +660,24 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *comp } static char* reg_names[] = { - (char*)"", (char*)"t1", (char*)"t2", (char*)"t3", - (char*)"te1", (char*)"te2", (char*)"s1", (char*)"s2", - (char*)"s3", (char*)"se1", (char*)"se2", (char*)"lcr" + (char*)"unused", (char*)"s1", (char*)"s2", (char*)"s3", + (char*)"se1", (char*)"se2", (char*)"p1", (char*)"p2", + (char*)"p3", (char*)"pe1", (char*)"pe2", (char*)"lc" }; static char* freg_names[] = { - (char*)"", (char*)"float_r1", (char*)"float_r2", (char*)"float_r3", (char*)"float_r4" + (char*)"unused", (char*)"f1", (char*)"f2", (char*)"f3", + (char*)"f4", (char*)"f5", (char*)"f6" }; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) #ifdef _WIN64 - #define SLJIT_PRINT_D "I64" +# define SLJIT_PRINT_D "I64" #else - #define SLJIT_PRINT_D "l" +# define SLJIT_PRINT_D "l" #endif #else - #define SLJIT_PRINT_D "" +# define SLJIT_PRINT_D "" #endif #define sljit_verbose_param(p, i) \ @@ -662,32 +729,32 @@ static SLJIT_CONST char* op_names[] = { (char*)"umul", (char*)"smul", (char*)"udiv", (char*)"sdiv", /* op1 */ (char*)"mov", (char*)"mov.ub", (char*)"mov.sb", (char*)"mov.uh", - (char*)"mov.sh", (char*)"mov.ui", (char*)"mov.si", (char*)"movu", - (char*)"movu.ub", (char*)"movu.sb", (char*)"movu.uh", (char*)"movu.sh", - (char*)"movu.ui", (char*)"movu.si", (char*)"not", (char*)"neg", - (char*)"clz", + (char*)"mov.sh", (char*)"mov.ui", (char*)"mov.si", (char*)"mov.p", + (char*)"movu", (char*)"movu.ub", (char*)"movu.sb", (char*)"movu.uh", + (char*)"movu.sh", (char*)"movu.ui", (char*)"movu.si", (char*)"movu.p", + (char*)"not", (char*)"neg", (char*)"clz", /* op2 */ (char*)"add", (char*)"addc", (char*)"sub", (char*)"subc", (char*)"mul", (char*)"and", (char*)"or", (char*)"xor", (char*)"shl", (char*)"lshr", (char*)"ashr", /* fop1 */ - (char*)"fcmp", (char*)"fmov", (char*)"fneg", (char*)"fabs", + (char*)"cmp", (char*)"mov", (char*)"neg", (char*)"abs", /* fop2 */ - (char*)"fadd", (char*)"fsub", (char*)"fmul", (char*)"fdiv" + (char*)"add", (char*)"sub", (char*)"mul", (char*)"div" }; static char* jump_names[] = { - (char*)"c_equal", (char*)"c_not_equal", - (char*)"c_less", (char*)"c_greater_equal", - (char*)"c_greater", (char*)"c_less_equal", - (char*)"c_sig_less", (char*)"c_sig_greater_equal", - (char*)"c_sig_greater", (char*)"c_sig_less_equal", - (char*)"c_overflow", (char*)"c_not_overflow", - (char*)"c_mul_overflow", (char*)"c_mul_not_overflow", - (char*)"c_float_equal", (char*)"c_float_not_equal", - (char*)"c_float_less", (char*)"c_float_greater_equal", - (char*)"c_float_greater", (char*)"c_float_less_equal", - (char*)"c_float_nan", (char*)"c_float_not_nan", + (char*)"equal", (char*)"not_equal", + (char*)"less", (char*)"greater_equal", + (char*)"greater", (char*)"less_equal", + (char*)"sig_less", (char*)"sig_greater_equal", + (char*)"sig_greater", (char*)"sig_less_equal", + (char*)"overflow", (char*)"not_overflow", + (char*)"mul_overflow", (char*)"mul_not_overflow", + (char*)"float_equal", (char*)"float_not_equal", + (char*)"float_less", (char*)"float_greater_equal", + (char*)"float_greater", (char*)"float_less_equal", + (char*)"float_unordered", (char*)"float_ordered", (char*)"jump", (char*)"fast_call", (char*)"call0", (char*)"call1", (char*)"call2", (char*)"call3" }; @@ -717,32 +784,32 @@ static SLJIT_INLINE void check_sljit_generate_code(struct sljit_compiler *compil #endif } -static SLJIT_INLINE void check_sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +static SLJIT_INLINE void check_sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(args); - SLJIT_UNUSED_ARG(temporaries); + SLJIT_UNUSED_ARG(scratches); SLJIT_UNUSED_ARG(saveds); SLJIT_UNUSED_ARG(local_size); SLJIT_ASSERT(args >= 0 && args <= 3); - SLJIT_ASSERT(temporaries >= 0 && temporaries <= SLJIT_NO_TMP_REGISTERS); + SLJIT_ASSERT(scratches >= 0 && scratches <= SLJIT_NO_TMP_REGISTERS); SLJIT_ASSERT(saveds >= 0 && saveds <= SLJIT_NO_GEN_REGISTERS); SLJIT_ASSERT(args <= saveds); SLJIT_ASSERT(local_size >= 0 && local_size <= SLJIT_MAX_LOCAL_SIZE); #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) - fprintf(compiler->verbose, " enter args=%d temporaries=%d saveds=%d local_size=%d\n", args, temporaries, saveds, local_size); + fprintf(compiler->verbose, " enter args=%d scratches=%d saveds=%d local_size=%d\n", args, scratches, saveds, local_size); #endif } -static SLJIT_INLINE void check_sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +static SLJIT_INLINE void check_sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(args); - SLJIT_UNUSED_ARG(temporaries); + SLJIT_UNUSED_ARG(scratches); SLJIT_UNUSED_ARG(saveds); SLJIT_UNUSED_ARG(local_size); @@ -754,17 +821,17 @@ static SLJIT_INLINE void check_sljit_set_context(struct sljit_compiler *compiler #endif SLJIT_ASSERT(args >= 0 && args <= 3); - SLJIT_ASSERT(temporaries >= 0 && temporaries <= SLJIT_NO_TMP_REGISTERS); + SLJIT_ASSERT(scratches >= 0 && scratches <= SLJIT_NO_TMP_REGISTERS); SLJIT_ASSERT(saveds >= 0 && saveds <= SLJIT_NO_GEN_REGISTERS); SLJIT_ASSERT(args <= saveds); SLJIT_ASSERT(local_size >= 0 && local_size <= SLJIT_MAX_LOCAL_SIZE); #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) - fprintf(compiler->verbose, " set_context args=%d temporaries=%d saveds=%d local_size=%d\n", args, temporaries, saveds, local_size); + fprintf(compiler->verbose, " set_context args=%d scratches=%d saveds=%d local_size=%d\n", args, scratches, saveds, local_size); #endif } -static SLJIT_INLINE void check_sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) +static SLJIT_INLINE void check_sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -774,7 +841,7 @@ static SLJIT_INLINE void check_sljit_emit_return(struct sljit_compiler *compiler #if (defined SLJIT_DEBUG && SLJIT_DEBUG) if (op != SLJIT_UNUSED) { - SLJIT_ASSERT(op >= SLJIT_MOV && op <= SLJIT_MOV_SI); + SLJIT_ASSERT(op >= SLJIT_MOV && op <= SLJIT_MOV_P); FUNCTION_CHECK_SRC(src, srcw); } else @@ -793,7 +860,7 @@ static SLJIT_INLINE void check_sljit_emit_return(struct sljit_compiler *compiler #endif } -static SLJIT_INLINE void check_sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw) +static SLJIT_INLINE void check_sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -812,7 +879,7 @@ static SLJIT_INLINE void check_sljit_emit_fast_enter(struct sljit_compiler *comp #endif } -static SLJIT_INLINE void check_sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw) +static SLJIT_INLINE void check_sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -831,7 +898,7 @@ static SLJIT_INLINE void check_sljit_emit_fast_return(struct sljit_compiler *com #endif } -static SLJIT_INLINE void check_sljit_emit_op0(struct sljit_compiler *compiler, int op) +static SLJIT_INLINE void check_sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -845,9 +912,9 @@ static SLJIT_INLINE void check_sljit_emit_op0(struct sljit_compiler *compiler, i #endif } -static SLJIT_INLINE void check_sljit_emit_op1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +static SLJIT_INLINE void check_sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -874,7 +941,8 @@ static SLJIT_INLINE void check_sljit_emit_op1(struct sljit_compiler *compiler, i #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) { fprintf(compiler->verbose, " %s%s%s%s%s%s%s%s ", !(op & SLJIT_INT_OP) ? "" : "i", op_names[GET_OPCODE(op)], - !(op & SLJIT_SET_E) ? "" : "E", !(op & SLJIT_SET_S) ? "" : "S", !(op & SLJIT_SET_U) ? "" : "U", !(op & SLJIT_SET_O) ? "" : "O", !(op & SLJIT_SET_C) ? "" : "C", !(op & SLJIT_KEEP_FLAGS) ? "" : "K"); + !(op & SLJIT_SET_E) ? "" : ".e", !(op & SLJIT_SET_S) ? "" : ".s", !(op & SLJIT_SET_U) ? "" : ".u", + !(op & SLJIT_SET_O) ? "" : ".o", !(op & SLJIT_SET_C) ? "" : ".c", !(op & SLJIT_KEEP_FLAGS) ? "" : ".k"); sljit_verbose_param(dst, dstw); fprintf(compiler->verbose, ", "); sljit_verbose_param(src, srcw); @@ -883,10 +951,10 @@ static SLJIT_INLINE void check_sljit_emit_op1(struct sljit_compiler *compiler, i #endif } -static SLJIT_INLINE void check_sljit_emit_op2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static SLJIT_INLINE void check_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) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -915,7 +983,8 @@ static SLJIT_INLINE void check_sljit_emit_op2(struct sljit_compiler *compiler, i #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) { fprintf(compiler->verbose, " %s%s%s%s%s%s%s%s ", !(op & SLJIT_INT_OP) ? "" : "i", op_names[GET_OPCODE(op)], - !(op & SLJIT_SET_E) ? "" : "E", !(op & SLJIT_SET_S) ? "" : "S", !(op & SLJIT_SET_U) ? "" : "U", !(op & SLJIT_SET_O) ? "" : "O", !(op & SLJIT_SET_C) ? "" : "C", !(op & SLJIT_KEEP_FLAGS) ? "" : "K"); + !(op & SLJIT_SET_E) ? "" : ".e", !(op & SLJIT_SET_S) ? "" : ".s", !(op & SLJIT_SET_U) ? "" : ".u", + !(op & SLJIT_SET_O) ? "" : ".o", !(op & SLJIT_SET_C) ? "" : ".c", !(op & SLJIT_KEEP_FLAGS) ? "" : ".k"); sljit_verbose_param(dst, dstw); fprintf(compiler->verbose, ", "); sljit_verbose_param(src1, src1w); @@ -926,14 +995,20 @@ static SLJIT_INLINE void check_sljit_emit_op2(struct sljit_compiler *compiler, i #endif } -static SLJIT_INLINE void check_sljit_get_register_index(int reg) +static SLJIT_INLINE void check_sljit_get_register_index(sljit_si reg) { SLJIT_UNUSED_ARG(reg); SLJIT_ASSERT(reg > 0 && reg <= SLJIT_NO_REGISTERS); } +static SLJIT_INLINE void check_sljit_get_float_register_index(sljit_si reg) +{ + SLJIT_UNUSED_ARG(reg); + SLJIT_ASSERT(reg > 0 && reg <= SLJIT_NO_FLOAT_REGISTERS); +} + static SLJIT_INLINE void check_sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, int size) + void *instruction, sljit_si size) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(instruction); @@ -941,9 +1016,9 @@ static SLJIT_INLINE void check_sljit_emit_op_custom(struct sljit_compiler *compi SLJIT_ASSERT(instruction); } -static SLJIT_INLINE void check_sljit_emit_fop1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +static SLJIT_INLINE void check_sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -961,7 +1036,7 @@ static SLJIT_INLINE void check_sljit_emit_fop1(struct sljit_compiler *compiler, #endif SLJIT_ASSERT(sljit_is_fpu_available()); - SLJIT_ASSERT(GET_OPCODE(op) >= SLJIT_FCMP && GET_OPCODE(op) <= SLJIT_FABS); + SLJIT_ASSERT(GET_OPCODE(op) >= SLJIT_CMPD && GET_OPCODE(op) <= SLJIT_ABSD); #if (defined SLJIT_DEBUG && SLJIT_DEBUG) FUNCTION_CHECK_OP(); FUNCTION_FCHECK(src, srcw); @@ -969,8 +1044,8 @@ static SLJIT_INLINE void check_sljit_emit_fop1(struct sljit_compiler *compiler, #endif #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s%s%s ", op_names[GET_OPCODE(op)], - !(op & SLJIT_SET_E) ? "" : "E", !(op & SLJIT_SET_S) ? "" : "S"); + fprintf(compiler->verbose, " %s%s%s%s ", op_names[GET_OPCODE(op)], (op & SLJIT_SINGLE_OP) ? "s" : "d", + !(op & SLJIT_SET_E) ? "" : ".e", !(op & SLJIT_SET_S) ? "" : ".s"); sljit_verbose_fparam(dst, dstw); fprintf(compiler->verbose, ", "); sljit_verbose_fparam(src, srcw); @@ -979,10 +1054,10 @@ static SLJIT_INLINE void check_sljit_emit_fop1(struct sljit_compiler *compiler, #endif } -static SLJIT_INLINE void check_sljit_emit_fop2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static SLJIT_INLINE void check_sljit_emit_fop2(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) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -995,7 +1070,7 @@ static SLJIT_INLINE void check_sljit_emit_fop2(struct sljit_compiler *compiler, SLJIT_UNUSED_ARG(src2w); SLJIT_ASSERT(sljit_is_fpu_available()); - SLJIT_ASSERT(GET_OPCODE(op) >= SLJIT_FADD && GET_OPCODE(op) <= SLJIT_FDIV); + SLJIT_ASSERT(GET_OPCODE(op) >= SLJIT_ADDD && GET_OPCODE(op) <= SLJIT_DIVD); #if (defined SLJIT_DEBUG && SLJIT_DEBUG) FUNCTION_CHECK_OP(); FUNCTION_FCHECK(src1, src1w); @@ -1004,7 +1079,7 @@ static SLJIT_INLINE void check_sljit_emit_fop2(struct sljit_compiler *compiler, #endif #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %s ", op_names[GET_OPCODE(op)]); + fprintf(compiler->verbose, " %s%s ", op_names[GET_OPCODE(op)], (op & SLJIT_SINGLE_OP) ? "s" : "d"); sljit_verbose_fparam(dst, dstw); fprintf(compiler->verbose, ", "); sljit_verbose_fparam(src1, src1w); @@ -1026,7 +1101,7 @@ static SLJIT_INLINE void check_sljit_emit_label(struct sljit_compiler *compiler) #endif } -static SLJIT_INLINE void check_sljit_emit_jump(struct sljit_compiler *compiler, int type) +static SLJIT_INLINE void check_sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -1043,13 +1118,13 @@ static SLJIT_INLINE void check_sljit_emit_jump(struct sljit_compiler *compiler, SLJIT_ASSERT((type & 0xff) >= SLJIT_C_EQUAL && (type & 0xff) <= SLJIT_CALL3); #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) - fprintf(compiler->verbose, " jump%s <%s>\n", !(type & SLJIT_REWRITABLE_JUMP) ? "" : "R", jump_names[type & 0xff]); + fprintf(compiler->verbose, " jump%s.%s\n", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r", jump_names[type & 0xff]); #endif } -static SLJIT_INLINE void check_sljit_emit_cmp(struct sljit_compiler *compiler, int type, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static SLJIT_INLINE void check_sljit_emit_cmp(struct sljit_compiler *compiler, sljit_si type, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(type); @@ -1058,7 +1133,7 @@ static SLJIT_INLINE void check_sljit_emit_cmp(struct sljit_compiler *compiler, i SLJIT_UNUSED_ARG(src2); SLJIT_UNUSED_ARG(src2w); - SLJIT_ASSERT(!(type & ~(0xff | SLJIT_INT_OP | SLJIT_REWRITABLE_JUMP))); + SLJIT_ASSERT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_INT_OP))); SLJIT_ASSERT((type & 0xff) >= SLJIT_C_EQUAL && (type & 0xff) <= SLJIT_C_SIG_LESS_EQUAL); #if (defined SLJIT_DEBUG && SLJIT_DEBUG) FUNCTION_CHECK_SRC(src1, src1w); @@ -1066,7 +1141,7 @@ static SLJIT_INLINE void check_sljit_emit_cmp(struct sljit_compiler *compiler, i #endif #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " %scmp%s <%s> ", !(type & SLJIT_INT_OP) ? "" : "i", !(type & SLJIT_REWRITABLE_JUMP) ? "" : "R", jump_names[type & 0xff]); + fprintf(compiler->verbose, " %scmp%s.%s ", !(type & SLJIT_INT_OP) ? "" : "i", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r", jump_names[type & 0xff]); sljit_verbose_param(src1, src1w); fprintf(compiler->verbose, ", "); sljit_verbose_param(src2, src2w); @@ -1075,9 +1150,9 @@ static SLJIT_INLINE void check_sljit_emit_cmp(struct sljit_compiler *compiler, i #endif } -static SLJIT_INLINE void check_sljit_emit_fcmp(struct sljit_compiler *compiler, int type, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static SLJIT_INLINE void check_sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_si type, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(type); @@ -1087,15 +1162,16 @@ static SLJIT_INLINE void check_sljit_emit_fcmp(struct sljit_compiler *compiler, SLJIT_UNUSED_ARG(src2w); SLJIT_ASSERT(sljit_is_fpu_available()); - SLJIT_ASSERT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP))); - SLJIT_ASSERT((type & 0xff) >= SLJIT_C_FLOAT_EQUAL && (type & 0xff) <= SLJIT_C_FLOAT_NOT_NAN); + SLJIT_ASSERT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_SINGLE_OP))); + SLJIT_ASSERT((type & 0xff) >= SLJIT_C_FLOAT_EQUAL && (type & 0xff) <= SLJIT_C_FLOAT_ORDERED); #if (defined SLJIT_DEBUG && SLJIT_DEBUG) FUNCTION_FCHECK(src1, src1w); FUNCTION_FCHECK(src2, src2w); #endif #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " fcmp%s <%s> ", !(type & SLJIT_REWRITABLE_JUMP) ? "" : "R", jump_names[type & 0xff]); + fprintf(compiler->verbose, " %scmp%s.%s ", (type & SLJIT_SINGLE_OP) ? "s" : "d", + !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r", jump_names[type & 0xff]); sljit_verbose_fparam(src1, src1w); fprintf(compiler->verbose, ", "); sljit_verbose_fparam(src2, src2w); @@ -1104,7 +1180,7 @@ static SLJIT_INLINE void check_sljit_emit_fcmp(struct sljit_compiler *compiler, #endif } -static SLJIT_INLINE void check_sljit_emit_ijump(struct sljit_compiler *compiler, int type, int src, sljit_w srcw) +static SLJIT_INLINE void check_sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -1112,45 +1188,68 @@ static SLJIT_INLINE void check_sljit_emit_ijump(struct sljit_compiler *compiler, SLJIT_UNUSED_ARG(src); SLJIT_UNUSED_ARG(srcw); +#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) + if (SLJIT_UNLIKELY(compiler->skip_checks)) { + compiler->skip_checks = 0; + return; + } +#endif + SLJIT_ASSERT(type >= SLJIT_JUMP && type <= SLJIT_CALL3); #if (defined SLJIT_DEBUG && SLJIT_DEBUG) FUNCTION_CHECK_SRC(src, srcw); #endif #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " ijump <%s> ", jump_names[type]); + fprintf(compiler->verbose, " ijump.%s ", jump_names[type]); sljit_verbose_param(src, srcw); fprintf(compiler->verbose, "\n"); } #endif } -static SLJIT_INLINE void check_sljit_emit_cond_value(struct sljit_compiler *compiler, int op, int dst, sljit_w dstw, int type) +static SLJIT_INLINE void check_sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw, + sljit_si type) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(op); SLJIT_UNUSED_ARG(dst); SLJIT_UNUSED_ARG(dstw); + SLJIT_UNUSED_ARG(src); + SLJIT_UNUSED_ARG(srcw); SLJIT_UNUSED_ARG(type); SLJIT_ASSERT(type >= SLJIT_C_EQUAL && type < SLJIT_JUMP); - SLJIT_ASSERT(op == SLJIT_MOV || GET_OPCODE(op) == SLJIT_OR); - SLJIT_ASSERT(GET_ALL_FLAGS(op) == 0 || GET_ALL_FLAGS(op) == SLJIT_SET_E || GET_ALL_FLAGS(op) == SLJIT_KEEP_FLAGS); + SLJIT_ASSERT(op == SLJIT_MOV || GET_OPCODE(op) == SLJIT_MOV_UI || GET_OPCODE(op) == SLJIT_MOV_SI + || (GET_OPCODE(op) >= SLJIT_AND && GET_OPCODE(op) <= SLJIT_XOR)); + SLJIT_ASSERT((op & (SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_O | SLJIT_SET_C)) == 0); + SLJIT_ASSERT((op & (SLJIT_SET_E | SLJIT_KEEP_FLAGS)) != (SLJIT_SET_E | SLJIT_KEEP_FLAGS)); #if (defined SLJIT_DEBUG && SLJIT_DEBUG) + if (GET_OPCODE(op) < SLJIT_ADD) { + SLJIT_ASSERT(src == SLJIT_UNUSED && srcw == 0); + } else { + SLJIT_ASSERT(src == dst && srcw == dstw); + } FUNCTION_CHECK_DST(dst, dstw); #endif #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) if (SLJIT_UNLIKELY(!!compiler->verbose)) { - fprintf(compiler->verbose, " cond_set%s%s <%s> ", !(op & SLJIT_SET_E) ? "" : "E", - !(op & SLJIT_KEEP_FLAGS) ? "" : "K", op_names[GET_OPCODE(op)]); + fprintf(compiler->verbose, " %sflags.%s%s%s ", !(op & SLJIT_INT_OP) ? "" : "i", + op_names[GET_OPCODE(op)], !(op & SLJIT_SET_E) ? "" : ".e", !(op & SLJIT_KEEP_FLAGS) ? "" : ".k"); sljit_verbose_param(dst, dstw); - fprintf(compiler->verbose, ", <%s>\n", jump_names[type]); + if (src != SLJIT_UNUSED) { + fprintf(compiler->verbose, ", "); + sljit_verbose_param(src, srcw); + } + fprintf(compiler->verbose, ", %s\n", jump_names[type]); } #endif } -static SLJIT_INLINE void check_sljit_get_local_base(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w offset) +static SLJIT_INLINE void check_sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(dst); @@ -1169,7 +1268,7 @@ static SLJIT_INLINE void check_sljit_get_local_base(struct sljit_compiler *compi #endif } -static SLJIT_INLINE void check_sljit_emit_const(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w init_value) +static SLJIT_INLINE void check_sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value) { /* If debug and verbose are disabled, all arguments are unused. */ SLJIT_UNUSED_ARG(compiler); @@ -1189,17 +1288,18 @@ static SLJIT_INLINE void check_sljit_emit_const(struct sljit_compiler *compiler, #endif } -static SLJIT_INLINE int emit_mov_before_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) +static SLJIT_INLINE sljit_si emit_mov_before_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) { /* Return if don't need to do anything. */ if (op == SLJIT_UNUSED) return SLJIT_SUCCESS; #if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE) - if (src == SLJIT_RETURN_REG && op == SLJIT_MOV) + /* At the moment the pointer size is always equal to sljit_sw. May be changed in the future. */ + if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_P)) return SLJIT_SUCCESS; #else - if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_UI || op == SLJIT_MOV_SI)) + if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_UI || op == SLJIT_MOV_SI || op == SLJIT_MOV_P)) return SLJIT_SUCCESS; #endif @@ -1236,32 +1336,36 @@ static SLJIT_INLINE int emit_mov_before_return(struct sljit_compiler *compiler, #define SLJIT_CPUINFO SLJIT_CPUINFO_PART1 SLJIT_CPUINFO_PART2 SLJIT_CPUINFO_PART3 #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - #include "sjx86c.c" +# include "sjx86c.c" #elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - #include "sjx86c.c" +# include "sjx86c.c" #elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) - #include "sjarmv5.c" +# include "sjarmv5.c" #elif (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) - #include "sjarmv5.c" +# include "sjarmv5.c" #elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) - #include "sjarmth2.c" +# include "sjarmth2.c" #elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - #include "sjppcc.c" +# include "sjppcc.c" #elif (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - #include "sjppcc.c" +# include "sjppcc.c" #elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - #include "sjmipsc.c" +# include "sjmipsc.c" +#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) +# include "sljitNativeSPARC_common.c" +#elif (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) +# include "sljitNativeTILEGX.c" #endif #if !(defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, int type, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_si type, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { /* Default compare for most architectures. */ - int flags, tmp_src, condition; - sljit_w tmp_srcw; + sljit_si flags, tmp_src, condition; + sljit_sw tmp_srcw; CHECK_ERROR_PTR(); check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w); @@ -1322,24 +1426,23 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler return sljit_emit_jump(compiler, condition | (type & SLJIT_REWRITABLE_JUMP)); } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, int type, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_si type, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { - int flags, condition; + sljit_si flags, condition; check_sljit_emit_fcmp(compiler, type, src1, src1w, src2, src2w); condition = type & 0xff; - if (condition <= SLJIT_C_FLOAT_NOT_EQUAL) - flags = SLJIT_SET_E; - else - flags = SLJIT_SET_S; + flags = (condition <= SLJIT_C_FLOAT_NOT_EQUAL) ? SLJIT_SET_E : SLJIT_SET_S; + if (type & SLJIT_SINGLE_OP) + flags |= SLJIT_SINGLE_OP; #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->skip_checks = 1; #endif - sljit_emit_fop1(compiler, SLJIT_FCMP | flags, src1, src1w, src2, src2w); + sljit_emit_fop1(compiler, SLJIT_CMPD | flags, src1, src1w, src2, src2w); #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->skip_checks = 1; @@ -1351,7 +1454,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compile #if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) && !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) -SLJIT_API_FUNC_ATTRIBUTE int sljit_get_local_base(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w offset) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset) { CHECK_ERROR(); check_sljit_get_local_base(compiler, dst, dstw, offset); @@ -1371,7 +1474,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_get_local_base(struct sljit_compiler *compile /* Empty function bodies for those machines, which are not (yet) supported. */ -SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() +SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void) { return "unsupported"; } @@ -1388,7 +1491,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compile SLJIT_ASSERT_STOP(); } -SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, int size) +SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_si size) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(size); @@ -1418,28 +1521,28 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code) SLJIT_ASSERT_STOP(); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(args); - SLJIT_UNUSED_ARG(temporaries); + SLJIT_UNUSED_ARG(scratches); SLJIT_UNUSED_ARG(saveds); SLJIT_UNUSED_ARG(local_size); SLJIT_ASSERT_STOP(); return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(args); - SLJIT_UNUSED_ARG(temporaries); + SLJIT_UNUSED_ARG(scratches); SLJIT_UNUSED_ARG(saveds); SLJIT_UNUSED_ARG(local_size); SLJIT_ASSERT_STOP(); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(op); @@ -1449,20 +1552,16 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(dst); SLJIT_UNUSED_ARG(dstw); - SLJIT_UNUSED_ARG(args); - SLJIT_UNUSED_ARG(temporaries); - SLJIT_UNUSED_ARG(saveds); - SLJIT_UNUSED_ARG(local_size); SLJIT_ASSERT_STOP(); return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(src); @@ -1471,7 +1570,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compi return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(op); @@ -1479,9 +1578,9 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +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) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(op); @@ -1493,10 +1592,10 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +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) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(op); @@ -1510,14 +1609,14 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg) { SLJIT_ASSERT_STOP(); return reg; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, int size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, + void *instruction, sljit_si size) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(instruction); @@ -1526,15 +1625,15 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compile return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void) { SLJIT_ASSERT_STOP(); return 0; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(op); @@ -1546,10 +1645,10 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, in return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(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) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(op); @@ -1570,7 +1669,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi return NULL; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, int type) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(type); @@ -1578,9 +1677,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile return NULL; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, int type, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_si type, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(type); @@ -1592,9 +1691,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler return NULL; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, int type, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_si type, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(type); @@ -1620,7 +1719,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw SLJIT_ASSERT_STOP(); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, int type, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(type); @@ -1630,18 +1729,23 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compiler, int op, int dst, sljit_w dstw, int type) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw, + sljit_si type) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(op); SLJIT_UNUSED_ARG(dst); SLJIT_UNUSED_ARG(dstw); + SLJIT_UNUSED_ARG(src); + SLJIT_UNUSED_ARG(srcw); SLJIT_UNUSED_ARG(type); SLJIT_ASSERT_STOP(); return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_get_local_base(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w offset) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(dst); @@ -1651,7 +1755,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_get_local_base(struct sljit_compiler *compile return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w initval) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw initval) { SLJIT_UNUSED_ARG(compiler); SLJIT_UNUSED_ARG(dst); @@ -1668,7 +1772,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad SLJIT_ASSERT_STOP(); } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant) { SLJIT_UNUSED_ARG(addr); SLJIT_UNUSED_ARG(new_constant); diff --git a/src/3rd/pcre/sjlir.h b/src/3rd/pcre/sjlir.h index b88d456c40..4a154cfeb3 100644 --- a/src/3rd/pcre/sjlir.h +++ b/src/3rd/pcre/sjlir.h @@ -34,12 +34,19 @@ Short description Advantages: - - The execution can be continued from any LIR instruction - In other words, jump into and out of the code is safe - - Both target of (conditional) jump and call instructions - and constants can be dynamically modified during runtime + - The execution can be continued from any LIR instruction. In other + words, it is possible to jump to any label from anywhere, even from + a code fragment, which is compiled later, if both compiled code + shares the same context. See sljit_emit_enter for more details + - Supports self modifying code: target of (conditional) jump and call + instructions and some constant values can be dynamically modified + during runtime - although it is not suggested to do it frequently - - very effective to cache an important value once + - can be used for inline caching: save an important value once + in the instruction stream + - since this feature limits the optimization possibilities, a + special flag must be passed at compile time when these + instructions are emitted - A fixed stack space can be allocated for local variables - The compiler is thread-safe - The compiler is highly configurable through preprocessor macros. @@ -47,19 +54,19 @@ threaded applications), and you can use your own system functions (including memory allocators). See sljitConfig.h Disadvantages: + - No automatic register allocation, and temporary results are + not stored on the stack. (hence the name comes) - Limited number of registers (only 6+4 integer registers, max 3+2 - temporary, max 3+2 saved and 4 floating point registers) + scratch, max 3+2 saved and 6 floating point registers) In practice: - This approach is very effective for interpreters - One of the saved registers typically points to a stack interface - - It can jump to any exception handler anytime (even for another - function. It is safe for SLJIT.) - - Fast paths can be modified during runtime reflecting the changes + - It can jump to any exception handler anytime (even if it belongs + to another function) + - Hot paths can be modified during runtime reflecting the changes of the fastest execution path of the dynamic language - SLJIT supports complex memory addressing modes - - mainly position independent code - - Optimizations (perhaps later) - - Only for basic blocks (when no labels inserted between LIR instructions) + - mainly position and context independent code (except some cases) For valgrind users: - pass --smc-check=all argument to valgrind, since JIT is a "self-modifying code" @@ -70,7 +77,7 @@ #endif /* The following header file defines useful macros for fine tuning -sljit based code generators. They are listed in the begining +sljit based code generators. They are listed in the beginning of sljitConfigInternal.h */ #include "sjconfi.h" @@ -99,12 +106,14 @@ of sljitConfigInternal.h */ #define SLJIT_UNUSED 0 -/* Temporary (scratch) registers may not preserve their values across function calls. */ -#define SLJIT_TEMPORARY_REG1 1 -#define SLJIT_TEMPORARY_REG2 2 -#define SLJIT_TEMPORARY_REG3 3 -/* Note: Extra Registers cannot be used for memory addressing. */ -/* Note: on x86-32, these registers are emulated (using stack loads & stores). */ +/* Scratch (temporary) registers whose may not preserve their values + across function calls. */ +#define SLJIT_SCRATCH_REG1 1 +#define SLJIT_SCRATCH_REG2 2 +#define SLJIT_SCRATCH_REG3 3 +/* Note: extra registers cannot be used for memory addressing. */ +/* Note: on x86-32, these registers are emulated (using stack + loads & stores). */ #define SLJIT_TEMPORARY_EREG1 4 #define SLJIT_TEMPORARY_EREG2 5 @@ -112,15 +121,17 @@ of sljitConfigInternal.h */ #define SLJIT_SAVED_REG1 6 #define SLJIT_SAVED_REG2 7 #define SLJIT_SAVED_REG3 8 -/* Note: Extra Registers cannot be used for memory addressing. */ -/* Note: on x86-32, these registers are emulated (using stack loads & stores). */ +/* Note: extra registers cannot be used for memory addressing. */ +/* Note: on x86-32, these registers are emulated (using stack + loads & stores). */ #define SLJIT_SAVED_EREG1 9 #define SLJIT_SAVED_EREG2 10 /* Read-only register (cannot be the destination of an operation). Only SLJIT_MEM1(SLJIT_LOCALS_REG) addressing mode is allowed since several ABIs has certain limitations about the stack layout. However - sljit_get_local_base() can be used to obtain the offset of a value. */ + sljit_get_local_base() can be used to obtain the offset of a value + on the stack. */ #define SLJIT_LOCALS_REG 11 /* Number of registers. */ @@ -130,15 +141,15 @@ of sljitConfigInternal.h */ /* Return with machine word. */ -#define SLJIT_RETURN_REG SLJIT_TEMPORARY_REG1 +#define SLJIT_RETURN_REG SLJIT_SCRATCH_REG1 /* x86 prefers specific registers for special purposes. In case of shift - by register it supports only SLJIT_TEMPORARY_REG3 for shift argument + by register it supports only SLJIT_SCRATCH_REG3 for shift argument (which is the src2 argument of sljit_emit_op2). If another register is used, sljit must exchange data between registers which cause a minor slowdown. Other architectures has no such limitation. */ -#define SLJIT_PREF_SHIFT_REG SLJIT_TEMPORARY_REG3 +#define SLJIT_PREF_SHIFT_REG SLJIT_SCRATCH_REG3 /* --------------------------------------------------------------------- */ /* Floating point registers */ @@ -147,12 +158,17 @@ of sljitConfigInternal.h */ /* Note: SLJIT_UNUSED as destination is not valid for floating point operations, since they cannot be used for setting flags. */ -/* Floating point operations are performed on double precision values. */ +/* Floating point operations are performed on double or + single precision values. */ -#define SLJIT_FLOAT_REG1 1 -#define SLJIT_FLOAT_REG2 2 -#define SLJIT_FLOAT_REG3 3 -#define SLJIT_FLOAT_REG4 4 +#define SLJIT_FLOAT_REG1 1 +#define SLJIT_FLOAT_REG2 2 +#define SLJIT_FLOAT_REG3 3 +#define SLJIT_FLOAT_REG4 4 +#define SLJIT_FLOAT_REG5 5 +#define SLJIT_FLOAT_REG6 6 + +#define SLJIT_NO_FLOAT_REGISTERS 6 /* --------------------------------------------------------------------- */ /* Main structures and functions */ @@ -161,6 +177,7 @@ of sljitConfigInternal.h */ struct sljit_memory_fragment { struct sljit_memory_fragment *next; sljit_uw used_size; + /* Must be aligned to sljit_sw. */ sljit_ub memory[1]; }; @@ -174,7 +191,7 @@ struct sljit_label { struct sljit_jump { struct sljit_jump *next; sljit_uw addr; - sljit_w flags; + sljit_sw flags; union { sljit_uw target; struct sljit_label* label; @@ -187,7 +204,7 @@ struct sljit_const { }; struct sljit_compiler { - int error; + sljit_si error; struct sljit_label *labels; struct sljit_jump *jumps; @@ -200,29 +217,29 @@ struct sljit_compiler { struct sljit_memory_fragment *abuf; /* Used local registers. */ - int temporaries; + sljit_si scratches; /* Used saved registers. */ - int saveds; + sljit_si saveds; /* Local stack size. */ - int local_size; + sljit_si local_size; /* Code size. */ sljit_uw size; /* For statistical purposes. */ sljit_uw executable_size; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - int args; - int locals_offset; - int temporaries_start; - int saveds_start; + sljit_si args; + sljit_si locals_offset; + sljit_si scratches_start; + sljit_si saveds_start; #endif #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - int mode32; + sljit_si mode32; #endif #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - int flags_saved; + sljit_si flags_saved; #endif #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) @@ -239,25 +256,36 @@ struct sljit_compiler { #if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) /* Temporary fields. */ sljit_uw shift_imm; - int cache_arg; - sljit_w cache_argw; + sljit_si cache_arg; + sljit_sw cache_argw; #endif #if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) - int cache_arg; - sljit_w cache_argw; + sljit_si cache_arg; + sljit_sw cache_argw; #endif #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - sljit_w imm; - int cache_arg; - sljit_w cache_argw; + sljit_sw imm; + sljit_si cache_arg; + sljit_sw cache_argw; #endif #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - int delay_slot; - int cache_arg; - sljit_w cache_argw; + sljit_si delay_slot; + sljit_si cache_arg; + sljit_sw cache_argw; +#endif + +#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) + sljit_si delay_slot; + sljit_si cache_arg; + sljit_sw cache_argw; +#endif + +#if (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) + sljit_si cache_arg; + sljit_sw cache_argw; #endif #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) @@ -266,11 +294,11 @@ struct sljit_compiler { #if (defined SLJIT_DEBUG && SLJIT_DEBUG) /* Local size passed to the functions. */ - int logical_local_size; + sljit_si logical_local_size; #endif #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) - int skip_checks; + sljit_si skip_checks; #endif }; @@ -281,22 +309,29 @@ struct sljit_compiler { /* Creates an sljit compiler. Returns NULL if failed. */ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void); -/* Free everything except the codes. */ + +/* Free everything except the compiled machine code. */ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler); -static SLJIT_INLINE int sljit_get_compiler_error(struct sljit_compiler *compiler) { return compiler->error; } +/* Returns the current error code. If an error is occurred, future sljit + calls which uses the same compiler argument returns early with the same + error code. Thus there is no need for checking the error after every + call, it is enough to do it before the code is compiled. Removing + these checks increases the performance of the compiling process. */ +static SLJIT_INLINE sljit_si sljit_get_compiler_error(struct sljit_compiler *compiler) { return compiler->error; } /* Allocate a small amount of memory. The size must be <= 64 bytes on 32 bit, - and <= 128 bytes on 64 bit architectures. The memory area is owned by the compiler, - and freed by sljit_free_compiler. The returned pointer is sizeof(sljit_w) aligned. - Excellent for allocating small blocks during the compiling, and no need to worry - about freeing them. The size is enough to contain at most 16 pointers. - If the size is outside of the range, the function will return with NULL, - but this return value does not indicate that there is no more memory (does - not set the compiler to out-of-memory status). + and <= 128 bytes on 64 bit architectures. The memory area is owned by the + compiler, and freed by sljit_free_compiler. The returned pointer is + sizeof(sljit_sw) aligned. Excellent for allocating small blocks during + the compiling, and no need to worry about freeing them. The size is + enough to contain at most 16 pointers. If the size is outside of the range, + the function will return with NULL. However, this return value does not + indicate that there is no more memory (does not set the current error code + of the compiler to out-of-memory status). */ -SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, int size); +SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_si size); #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) /* Passing NULL disables verbose. */ @@ -307,15 +342,17 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code); /* - After the code generation we can retrieve the allocated executable memory size, - although this area may not be fully filled with instructions depending on some - optimizations. This function is useful only for statistical purposes. + After the machine code generation is finished we can retrieve the allocated + executable memory size, although this area may not be fully filled with + instructions depending on some optimizations. This function is useful only + for statistical purposes. Before a successful code generation, this function returns with 0. */ static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler *compiler) { return compiler->executable_size; } -/* Instruction generation. Returns with error code. */ +/* Instruction generation. Returns with any error code. If there is no + error, they return with SLJIT_SUCCESS. */ /* The executable code is basically a function call from the viewpoint of @@ -326,8 +363,8 @@ static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler for the executable code and moves function arguments to the saved registers. The number of arguments are specified in the "args" parameter and the first argument goes to SLJIT_SAVED_REG1, the second - goes to SLJIT_SAVED_REG2 and so on. The number of temporary and - saved registers are passed in "temporaries" and "saveds" arguments + goes to SLJIT_SAVED_REG2 and so on. The number of scratch and + saved registers are passed in "scratches" and "saveds" arguments respectively. Since the saved registers contains the arguments, "args" must be less or equal than "saveds". The sljit_emit_enter is also capable of allocating a stack space for local variables. The @@ -338,54 +375,53 @@ static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler SLJIT_LOCALS_REG + local_size (exclusive) can be modified freely until the function returns. The stack space is uninitialized. - Note: every call of sljit_emit_enter and sljit_set_context overwrites - the previous context. */ + Note: every call of sljit_emit_enter and sljit_set_context + overwrites the previous context. */ #define SLJIT_MAX_LOCAL_SIZE 65536 -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, - int args, int temporaries, int saveds, int local_size); +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, + sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size); /* The machine code has a context (which contains the local stack space size, number of used registers, etc.) which initialized by sljit_emit_enter. Several functions (like sljit_emit_return) requres this context to be able to generate the appropriate code. However, some code fragments (like inline cache) may have no normal entry point so their context is unknown for the compiler. Using the - function below we can specify thir context. + function below we can specify their context. Note: every call of sljit_emit_enter and sljit_set_context overwrites the previous context. */ -/* Note: multiple calls of this function overwrites the previous call. */ - SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, - int args, int temporaries, int saveds, int local_size); + sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size); /* Return from machine code. The op argument can be SLJIT_UNUSED which means the function does not return with anything or any opcode between SLJIT_MOV and - SLJIT_MOV_SI (see sljit_emit_op1). As for src and srcw they must be 0 if op + SLJIT_MOV_P (see sljit_emit_op1). As for src and srcw they must be 0 if op is SLJIT_UNUSED, otherwise see below the description about source and destination arguments. */ -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, - int src, sljit_w srcw); -/* Really fast calling method for utility functions inside sljit (see SLJIT_FAST_CALL). - All registers and even the stack frame is passed to the callee. The return address is - preserved in dst/dstw by sljit_emit_fast_enter, and sljit_emit_fast_return can - use this as a return value later. */ +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, + sljit_si src, sljit_sw srcw); -/* Note: only for sljit specific, non ABI compilant calls. Fast, since only a few machine instructions - are needed. Excellent for small uility functions, where saving registers and setting up - a new stack frame would cost too much performance. However, it is still possible to return - to the address of the caller (or anywhere else). */ +/* Fast calling mechanism for utility functions (see SLJIT_FAST_CALL). All registers and + even the stack frame is passed to the callee. The return address is preserved in + dst/dstw by sljit_emit_fast_enter (the type of the value stored by this function + is sljit_p), and sljit_emit_fast_return can use this as a return value later. */ + +/* Note: only for sljit specific, non ABI compilant calls. Fast, since only a few machine + instructions are needed. Excellent for small uility functions, where saving registers + and setting up a new stack frame would cost too much performance. However, it is still + possible to return to the address of the caller (or anywhere else). */ /* Note: flags are not changed (unlike sljit_emit_enter / sljit_emit_return). */ /* Note: although sljit_emit_fast_return could be replaced by an ijump, it is not suggested, since many architectures do clever branch prediction on call / return instruction pairs. */ -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw); -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw); +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw); +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw); /* Source and destination values for arithmetical instructions @@ -394,7 +430,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compi [imm] - absolute immediate memory address [reg+imm] - indirect memory address [reg+(reg<addr; } static SLJIT_INLINE sljit_uw sljit_get_jump_addr(struct sljit_jump *jump) { return jump->addr; } @@ -767,22 +900,22 @@ static SLJIT_INLINE sljit_uw sljit_get_const_addr(struct sljit_const *const_) { /* Only the address is required to rewrite the code. */ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr); -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant); +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant); /* --------------------------------------------------------------------- */ /* Miscellaneous utility functions */ /* --------------------------------------------------------------------- */ #define SLJIT_MAJOR_VERSION 0 -#define SLJIT_MINOR_VERSION 88 +#define SLJIT_MINOR_VERSION 91 -/* Get the human readable name of the platfrom. - Can be useful for debugging on platforms like ARM, where ARM and - Thumb2 functions can be mixed. */ +/* Get the human readable name of the platform. Can be useful on platforms + like ARM, where ARM and Thumb2 functions can be mixed, and + it is useful to know the type of the code generator. */ SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void); -/* Portble helper function to get an offset of a member. */ -#define SLJIT_OFFSETOF(base, member) ((sljit_w)(&((base*)0x10)->member) - 0x10) +/* Portable helper function to get an offset of a member. */ +#define SLJIT_OFFSETOF(base, member) ((sljit_sw)(&((base*)0x10)->member) - 0x10) #if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) /* This global lock is useful to compile common functions. */ @@ -831,32 +964,32 @@ SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack* st since the growth ratio can be added to the current limit, and sljit_stack_resize will do all the necessary checks. The fields of the stack are not changed if sljit_stack_resize fails. */ -SLJIT_API_FUNC_ATTRIBUTE sljit_w SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit); +SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit); #endif /* (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) */ #if !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) /* Get the entry address of a given function. */ -#define SLJIT_FUNC_OFFSET(func_name) ((sljit_w)func_name) +#define SLJIT_FUNC_OFFSET(func_name) ((sljit_sw)func_name) #else /* !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) */ /* All JIT related code should be placed in the same context (library, binary, etc.). */ -#define SLJIT_FUNC_OFFSET(func_name) ((sljit_w)*(void**)func_name) +#define SLJIT_FUNC_OFFSET(func_name) (*(sljit_sw*)(void*)func_name) /* For powerpc64, the function pointers point to a context descriptor. */ struct sljit_function_context { - sljit_w addr; - sljit_w r2; - sljit_w r11; + sljit_sw addr; + sljit_sw r2; + sljit_sw r11; }; /* Fill the context arguments using the addr and the function. If func_ptr is NULL, it will not be set to the address of context If addr is NULL, the function address also comes from the func pointer. */ -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_w addr, void* func); +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_sw addr, void* func); #endif /* !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) */ diff --git a/src/3rd/pcre/sjmips32.c b/src/3rd/pcre/sjmips32.c index c0cc8b58bb..f8c214863d 100644 --- a/src/3rd/pcre/sjmips32.c +++ b/src/3rd/pcre/sjmips32.c @@ -26,7 +26,7 @@ /* mips 32-bit arch dependent functions. */ -static int load_immediate(struct sljit_compiler *compiler, int dst_ar, sljit_w imm) +static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm) { if (!(imm & ~0xffff)) return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar); @@ -66,12 +66,92 @@ static int load_immediate(struct sljit_compiler *compiler, int dst_ar, sljit_w i FAIL_IF(push_inst(compiler, op_norm | S(src2) | T(src1) | D(dst), DR(dst))); \ } -static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags, - int dst, int src1, sljit_w src2) +static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags, + sljit_si dst, sljit_si src1, sljit_sw src2) { - int overflow_ra = 0; + sljit_si overflow_ra = 0; switch (GET_OPCODE(op)) { + case SLJIT_MOV: + case SLJIT_MOV_UI: + case SLJIT_MOV_SI: + case SLJIT_MOV_P: + SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + if (dst != src2) + return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst)); + return SLJIT_SUCCESS; + + case SLJIT_MOV_UB: + case SLJIT_MOV_SB: + SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { + if (op == SLJIT_MOV_SB) { +#if (defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64) + return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst)); +#else + FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(24), DR(dst))); + return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(24), DR(dst)); +#endif + } + return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst)); + } + else if (dst != src2) + SLJIT_ASSERT_STOP(); + return SLJIT_SUCCESS; + + case SLJIT_MOV_UH: + case SLJIT_MOV_SH: + SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { + if (op == SLJIT_MOV_SH) { +#if (defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64) + return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst)); +#else + FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst))); + return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst)); +#endif + } + return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst)); + } + else if (dst != src2) + SLJIT_ASSERT_STOP(); + return SLJIT_SUCCESS; + + case SLJIT_NOT: + SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); + if (op & SLJIT_SET_E) + FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); + if (CHECK_FLAGS(SLJIT_SET_E)) + FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst))); + return SLJIT_SUCCESS; + + case SLJIT_CLZ: + SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); +#if (defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64) + if (op & SLJIT_SET_E) + FAIL_IF(push_inst(compiler, CLZ | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG)); + if (CHECK_FLAGS(SLJIT_SET_E)) + FAIL_IF(push_inst(compiler, CLZ | S(src2) | T(dst) | D(dst), DR(dst))); +#else + if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) { + FAIL_IF(push_inst(compiler, SRL | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG)); + return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG); + } + /* Nearly all instructions are unmovable in the following sequence. */ + FAIL_IF(push_inst(compiler, ADDU_W | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1))); + /* Check zero. */ + FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS)); + FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(32), UNMOVABLE_INS)); + FAIL_IF(push_inst(compiler, ADDIU_W | SA(0) | T(dst) | IMM(-1), DR(dst))); + /* Loop for searching the highest bit. */ + FAIL_IF(push_inst(compiler, ADDIU_W | S(dst) | T(dst) | IMM(1), DR(dst))); + FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS)); + FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS)); + if (op & SLJIT_SET_E) + return push_inst(compiler, ADDU_W | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG); +#endif + return SLJIT_SUCCESS; + case SLJIT_ADD: if (flags & SRC2_IMM) { if (op & SLJIT_SET_O) { @@ -293,97 +373,16 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, case SLJIT_ASHR: EMIT_SHIFT(SRA, SRAV); return SLJIT_SUCCESS; - - case SLJIT_MOV: - case SLJIT_MOV_UI: - case SLJIT_MOV_SI: - SLJIT_ASSERT(src1 == TMP_REG1); - if (dst != src2) - return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst)); - return SLJIT_SUCCESS; - - case SLJIT_MOV_UB: - case SLJIT_MOV_SB: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_SB) { -#if (defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64) - return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst)); -#else - FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(24), DR(dst))); - return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(24), DR(dst)); -#endif - } - return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst)); - } - else if (dst != src2) - SLJIT_ASSERT_STOP(); - return SLJIT_SUCCESS; - - case SLJIT_MOV_UH: - case SLJIT_MOV_SH: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_SH) { -#if (defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64) - return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst)); -#else - FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst))); - return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst)); -#endif - } - return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst)); - } - else if (dst != src2) - SLJIT_ASSERT_STOP(); - return SLJIT_SUCCESS; - - case SLJIT_NOT: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); - if (op & SLJIT_SET_E) - FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); - if (CHECK_FLAGS(SLJIT_SET_E)) - FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst))); - return SLJIT_SUCCESS; - - case SLJIT_CLZ: - SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM)); -#if (defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64) - if (op & SLJIT_SET_E) - FAIL_IF(push_inst(compiler, CLZ | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG)); - if (CHECK_FLAGS(SLJIT_SET_E)) - FAIL_IF(push_inst(compiler, CLZ | S(src2) | T(dst) | D(dst), DR(dst))); -#else - if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) { - FAIL_IF(push_inst(compiler, SRL | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG)); - return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG); - } - /* Nearly all instructions are unmovable in the following sequence. */ - FAIL_IF(push_inst(compiler, ADDU_W | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1))); - /* Check zero. */ - FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(6), UNMOVABLE_INS)); - FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(32), UNMOVABLE_INS)); - /* Check sign bit. */ - FAIL_IF(push_inst(compiler, BLTZ | S(TMP_REG1) | IMM(4), UNMOVABLE_INS)); - FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(0), UNMOVABLE_INS)); - /* Loop for searching the highest bit. */ - FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), DR(TMP_REG1))); - FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS)); - FAIL_IF(push_inst(compiler, ADDIU_W | S(dst) | T(dst) | IMM(1), UNMOVABLE_INS)); - if (op & SLJIT_SET_E) - return push_inst(compiler, ADDU_W | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG); -#endif - return SLJIT_SUCCESS; } SLJIT_ASSERT_STOP(); return SLJIT_SUCCESS; } -static SLJIT_INLINE int emit_const(struct sljit_compiler *compiler, int reg, sljit_w init_value) +static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw init_value) { - FAIL_IF(push_inst(compiler, LUI | T(reg) | IMM(init_value >> 16), DR(reg))); - return push_inst(compiler, ORI | S(reg) | T(reg) | IMM(init_value), DR(reg)); + FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst))); + return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst)); } SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr) @@ -395,7 +394,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad SLJIT_CACHE_FLUSH(inst, inst + 2); } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant) { sljit_ins *inst = (sljit_ins*)addr; diff --git a/src/3rd/pcre/sjmipsc.c b/src/3rd/pcre/sjmipsc.c index ee3a4c7e07..8849b057b1 100644 --- a/src/3rd/pcre/sjmipsc.c +++ b/src/3rd/pcre/sjmipsc.c @@ -24,13 +24,17 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() -{ - return "MIPS" SLJIT_CPUINFO; -} - /* Latest MIPS architecture. */ -/* Detect SLJIT_MIPS_32_64 */ +/* Automatically detect SLJIT_MIPS_32_64 */ + +SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void) +{ +#if (defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64) + return "MIPS(32)" SLJIT_CPUINFO; +#else + return "MIPS III" SLJIT_CPUINFO; +#endif +} /* Length of an instruction word Both for mips-32 and mips-64 */ @@ -41,15 +45,15 @@ typedef sljit_ui sljit_ins; #define TMP_REG3 (SLJIT_NO_REGISTERS + 3) /* For position independent code, t9 must contain the function address. */ -#define PIC_ADDR_REG TMP_REG2 +#define PIC_ADDR_REG TMP_REG2 /* TMP_EREG1 is used mainly for literal encoding on 64 bit. */ -#define TMP_EREG1 15 -#define TMP_EREG2 24 +#define TMP_EREG1 15 +#define TMP_EREG2 24 /* Floating point status register. */ -#define FCSR_REG 31 +#define FCSR_REG 31 /* Return address register. */ -#define RETURN_ADDR_REG 31 +#define RETURN_ADDR_REG 31 /* Flags are keept in volatile registers. */ #define EQUAL_FLAG 7 @@ -60,8 +64,12 @@ typedef sljit_ui sljit_ins; #define GREATER_FLAG 13 #define OVERFLOW_FLAG 14 -#define TMP_FREG1 (SLJIT_FLOAT_REG4 + 1) -#define TMP_FREG2 (SLJIT_FLOAT_REG4 + 2) +#define TMP_FREG1 (0) +#define TMP_FREG2 ((SLJIT_FLOAT_REG6 + 1) << 1) + +static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 4] = { + 0, 2, 5, 6, 3, 8, 16, 17, 18, 19, 20, 29, 4, 25, 9 +}; /* --------------------------------------------------------------------- */ /* Instrucion forms */ @@ -74,19 +82,20 @@ typedef sljit_ui sljit_ins; #define SA(s) ((s) << 21) #define TA(t) ((t) << 16) #define DA(d) ((d) << 11) -#define FT(t) ((t) << (16 + 1)) -#define FS(s) ((s) << (11 + 1)) -#define FD(d) ((d) << (6 + 1)) +#define FT(t) ((t) << 16) +#define FS(s) ((s) << 11) +#define FD(d) ((d) << 6) #define IMM(imm) ((imm) & 0xffff) #define SH_IMM(imm) ((imm & 0x1f) << 6) #define DR(dr) (reg_map[dr]) #define HI(opcode) ((opcode) << 26) #define LO(opcode) (opcode) -#define FMT_D (17 << 21) +/* S = (16 << 21) D = (17 << 21) */ +#define FMT_SD (16 << 21) -#define ABS_D (HI(17) | FMT_D | LO(5)) -#define ADD_D (HI(17) | FMT_D | LO(0)) +#define ABS_fmt (HI(17) | FMT_SD | LO(5)) +#define ADD_fmt (HI(17) | FMT_SD | LO(0)) #define ADDU (HI(0) | LO(33)) #define ADDIU (HI(9)) #define AND (HI(0) | LO(36)) @@ -102,37 +111,35 @@ typedef sljit_ui sljit_ins; #define BLTZ (HI(1) | (0 << 16)) #define BNE (HI(5)) #define BREAK (HI(0) | LO(13)) -#define C_UN_D (HI(17) | FMT_D | LO(49)) -#define C_UEQ_D (HI(17) | FMT_D | LO(51)) -#define C_ULE_D (HI(17) | FMT_D | LO(55)) -#define C_ULT_D (HI(17) | FMT_D | LO(53)) +#define CFC1 (HI(17) | (2 << 21)) +#define C_UN_fmt (HI(17) | FMT_SD | LO(49)) +#define C_UEQ_fmt (HI(17) | FMT_SD | LO(51)) +#define C_ULE_fmt (HI(17) | FMT_SD | LO(55)) +#define C_ULT_fmt (HI(17) | FMT_SD | LO(53)) #define DIV (HI(0) | LO(26)) #define DIVU (HI(0) | LO(27)) -#define DIV_D (HI(17) | FMT_D | LO(3)) +#define DIV_fmt (HI(17) | FMT_SD | LO(3)) #define J (HI(2)) #define JAL (HI(3)) #define JALR (HI(0) | LO(9)) #define JR (HI(0) | LO(8)) #define LD (HI(55)) -#define LDC1 (HI(53)) #define LUI (HI(15)) #define LW (HI(35)) -#define NEG_D (HI(17) | FMT_D | LO(7)) #define MFHI (HI(0) | LO(16)) #define MFLO (HI(0) | LO(18)) -#define MOV_D (HI(17) | FMT_D | LO(6)) -#define CFC1 (HI(17) | (2 << 21)) +#define MOV_fmt (HI(17) | FMT_SD | LO(6)) #define MOVN (HI(0) | LO(11)) #define MOVZ (HI(0) | LO(10)) -#define MUL_D (HI(17) | FMT_D | LO(2)) +#define MUL_fmt (HI(17) | FMT_SD | LO(2)) #define MULT (HI(0) | LO(24)) #define MULTU (HI(0) | LO(25)) +#define NEG_fmt (HI(17) | FMT_SD | LO(7)) #define NOP (HI(0) | LO(0)) #define NOR (HI(0) | LO(39)) #define OR (HI(0) | LO(37)) #define ORI (HI(13)) #define SD (HI(63)) -#define SDC1 (HI(61)) #define SLT (HI(0) | LO(42)) #define SLTI (HI(10)) #define SLTIU (HI(11)) @@ -143,7 +150,7 @@ typedef sljit_ui sljit_ins; #define SRLV (HI(0) | LO(6)) #define SRA (HI(0) | LO(3)) #define SRAV (HI(0) | LO(7)) -#define SUB_D (HI(17) | FMT_D | LO(1)) +#define SUB_fmt (HI(17) | FMT_SD | LO(1)) #define SUBU (HI(0) | LO(35)) #define SW (HI(43)) #define XOR (HI(0) | LO(38)) @@ -172,14 +179,12 @@ typedef sljit_ui sljit_ins; #define SIMM_MIN (-0x8000) #define UIMM_MAX (0xffff) -static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 6] = { - 0, 2, 5, 6, 3, 8, 16, 17, 18, 19, 20, 29, 4, 25, 9 -}; - /* dest_reg is the absolute name of the register Useful for reordering instructions in the delay slot. */ -static int push_inst(struct sljit_compiler *compiler, sljit_ins ins, int delay_slot) +static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_si delay_slot) { + SLJIT_ASSERT(delay_slot == MOVABLE_INS || delay_slot >= UNMOVABLE_INS + || delay_slot == ((ins >> 11) & 0x1f) || delay_slot == ((ins >> 16) & 0x1f)); sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins)); FAIL_IF(!ptr); *ptr = ins; @@ -188,14 +193,14 @@ static int push_inst(struct sljit_compiler *compiler, sljit_ins ins, int delay_s return SLJIT_SUCCESS; } -static SLJIT_INLINE sljit_ins invert_branch(int flags) +static SLJIT_INLINE sljit_ins invert_branch(sljit_si flags) { return (flags & IS_BIT26_COND) ? (1 << 26) : (1 << 16); } static SLJIT_INLINE sljit_ins* optimize_jump(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code) { - sljit_w diff; + sljit_sw diff; sljit_uw target_addr; sljit_ins *inst; sljit_ins saved_inst; @@ -215,7 +220,7 @@ static SLJIT_INLINE sljit_ins* optimize_jump(struct sljit_jump *jump, sljit_ins /* B instructions. */ if (jump->flags & IS_MOVABLE) { - diff = ((sljit_w)target_addr - (sljit_w)(inst)) >> 2; + diff = ((sljit_sw)target_addr - (sljit_sw)(inst)) >> 2; if (diff <= SIMM_MAX && diff >= SIMM_MIN) { jump->flags |= PATCH_B; @@ -233,7 +238,7 @@ static SLJIT_INLINE sljit_ins* optimize_jump(struct sljit_jump *jump, sljit_ins } } - diff = ((sljit_w)target_addr - (sljit_w)(inst + 1)) >> 2; + diff = ((sljit_sw)target_addr - (sljit_sw)(inst + 1)) >> 2; if (diff <= SIMM_MAX && diff >= SIMM_MIN) { jump->flags |= PATCH_B; @@ -335,7 +340,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) jump->addr = (sljit_uw)(code_ptr - 3); #else - jump->addr = (sljit_uw)(code_ptr - 6); +#error "Implementation required" #endif code_ptr = optimize_jump(jump, code_ptr, code); jump = jump->next; @@ -361,7 +366,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); - SLJIT_ASSERT(code_ptr - code <= (int)compiler->size); + SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); jump = compiler->jumps; while (jump) { @@ -370,8 +375,8 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil buf_ptr = (sljit_ins*)jump->addr; if (jump->flags & PATCH_B) { - addr = (sljit_w)(addr - (jump->addr + sizeof(sljit_ins))) >> 2; - SLJIT_ASSERT((sljit_w)addr <= SIMM_MAX && (sljit_w)addr >= SIMM_MIN); + addr = (sljit_sw)(addr - (jump->addr + sizeof(sljit_ins))) >> 2; + SLJIT_ASSERT((sljit_sw)addr <= SIMM_MAX && (sljit_sw)addr >= SIMM_MIN); buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | (addr & 0xffff); break; } @@ -386,17 +391,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 16) & 0xffff); buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | (addr & 0xffff); #else - buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 48) & 0xffff); - buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | ((addr >> 32) & 0xffff); - buf_ptr[3] = (buf_ptr[3] & 0xffff0000) | ((addr >> 16) & 0xffff); - buf_ptr[4] = (buf_ptr[4] & 0xffff0000) | (addr & 0xffff); +#error "Implementation required" #endif } while (0); jump = jump->next; } compiler->error = SLJIT_ERR_COMPILED; - compiler->executable_size = compiler->size * sizeof(sljit_ins); + compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins); #ifndef __GNUC__ SLJIT_CACHE_FLUSH(code, code_ptr); #else @@ -406,41 +408,43 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil return code; } +/* --------------------------------------------------------------------- */ +/* Entry, exit */ +/* --------------------------------------------------------------------- */ + /* Creates an index in data_transfer_insts array. */ +#define LOAD_DATA 0x01 #define WORD_DATA 0x00 -#define BYTE_DATA 0x01 -#define HALF_DATA 0x02 -#define INT_DATA 0x03 -#define SIGNED_DATA 0x04 -#define LOAD_DATA 0x08 +#define BYTE_DATA 0x02 +#define HALF_DATA 0x04 +#define INT_DATA 0x06 +#define SIGNED_DATA 0x08 +/* Separates integer and floating point registers */ +#define GPR_REG 0x0f +#define DOUBLE_DATA 0x10 -#define MEM_MASK 0x0f +#define MEM_MASK 0x1f -#define WRITE_BACK 0x00010 -#define ARG_TEST 0x00020 -#define CUMULATIVE_OP 0x00040 -#define LOGICAL_OP 0x00080 -#define IMM_OP 0x00100 -#define SRC2_IMM 0x00200 +#define WRITE_BACK 0x00020 +#define ARG_TEST 0x00040 +#define ALT_KEEP_CACHE 0x00080 +#define CUMULATIVE_OP 0x00100 +#define LOGICAL_OP 0x00200 +#define IMM_OP 0x00400 +#define SRC2_IMM 0x00800 -#define UNUSED_DEST 0x00400 -#define REG_DEST 0x00800 -#define REG1_SOURCE 0x01000 -#define REG2_SOURCE 0x02000 -#define SLOW_SRC1 0x04000 -#define SLOW_SRC2 0x08000 -#define SLOW_DEST 0x10000 +#define UNUSED_DEST 0x01000 +#define REG_DEST 0x02000 +#define REG1_SOURCE 0x04000 +#define REG2_SOURCE 0x08000 +#define SLOW_SRC1 0x10000 +#define SLOW_SRC2 0x20000 +#define SLOW_DEST 0x40000 /* Only these flags are set. UNUSED_DEST is not set when no flags should be set. */ #define CHECK_FLAGS(list) \ (!(flags & UNUSED_DEST) || (op & GET_FLAGS(~(list)))) -#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#include "sjmips32.c" -#else -#include "sljitNativeMIPS_64.c" -#endif - #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) #define STACK_STORE SW #define STACK_LOAD LW @@ -449,25 +453,26 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil #define STACK_LOAD LD #endif -static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w); +#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) +#include "sjmips32.c" +#else +#include "sljitNativeMIPS_64.c" +#endif -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { sljit_ins base; CHECK_ERROR(); - check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size); + check_sljit_emit_enter(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; #endif - local_size += (saveds + 1 + 4) * sizeof(sljit_w); + local_size += (saveds + 1 + 4) * sizeof(sljit_sw); local_size = (local_size + 15) & ~0xf; compiler->local_size = local_size; @@ -484,17 +489,17 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i local_size = 0; } - FAIL_IF(push_inst(compiler, STACK_STORE | base | TA(RETURN_ADDR_REG) | IMM(local_size - 1 * (int)sizeof(sljit_w)), MOVABLE_INS)); + FAIL_IF(push_inst(compiler, STACK_STORE | base | TA(RETURN_ADDR_REG) | IMM(local_size - 1 * (sljit_si)sizeof(sljit_sw)), MOVABLE_INS)); if (saveds >= 1) - FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_REG1) | IMM(local_size - 2 * (int)sizeof(sljit_w)), MOVABLE_INS)); + FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_REG1) | IMM(local_size - 2 * (sljit_si)sizeof(sljit_sw)), MOVABLE_INS)); if (saveds >= 2) - FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_REG2) | IMM(local_size - 3 * (int)sizeof(sljit_w)), MOVABLE_INS)); + FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_REG2) | IMM(local_size - 3 * (sljit_si)sizeof(sljit_sw)), MOVABLE_INS)); if (saveds >= 3) - FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_REG3) | IMM(local_size - 4 * (int)sizeof(sljit_w)), MOVABLE_INS)); + FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_REG3) | IMM(local_size - 4 * (sljit_si)sizeof(sljit_sw)), MOVABLE_INS)); if (saveds >= 4) - FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_EREG1) | IMM(local_size - 5 * (int)sizeof(sljit_w)), MOVABLE_INS)); + FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_EREG1) | IMM(local_size - 5 * (sljit_si)sizeof(sljit_sw)), MOVABLE_INS)); if (saveds >= 5) - FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_EREG2) | IMM(local_size - 6 * (int)sizeof(sljit_w)), MOVABLE_INS)); + FAIL_IF(push_inst(compiler, STACK_STORE | base | T(SLJIT_SAVED_EREG2) | IMM(local_size - 6 * (sljit_si)sizeof(sljit_sw)), MOVABLE_INS)); if (args >= 1) FAIL_IF(push_inst(compiler, ADDU_W | SA(4) | TA(0) | D(SLJIT_SAVED_REG1), DR(SLJIT_SAVED_REG1))); @@ -506,29 +511,28 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { CHECK_ERROR_VOID(); - check_sljit_set_context(compiler, args, temporaries, saveds, local_size); + check_sljit_set_context(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; #endif - local_size += (saveds + 1 + 4) * sizeof(sljit_w); + local_size += (saveds + 1 + 4) * sizeof(sljit_sw); compiler->local_size = (local_size + 15) & ~0xf; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) { - int local_size; + sljit_si local_size; sljit_ins base; CHECK_ERROR(); check_sljit_emit_return(compiler, op, src, srcw); - ADJUST_LOCAL_OFFSET(src, srcw); FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); @@ -542,17 +546,17 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, local_size = 0; } - FAIL_IF(push_inst(compiler, STACK_LOAD | base | TA(RETURN_ADDR_REG) | IMM(local_size - 1 * (int)sizeof(sljit_w)), RETURN_ADDR_REG)); + FAIL_IF(push_inst(compiler, STACK_LOAD | base | TA(RETURN_ADDR_REG) | IMM(local_size - 1 * (sljit_si)sizeof(sljit_sw)), RETURN_ADDR_REG)); if (compiler->saveds >= 5) - FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_EREG2) | IMM(local_size - 6 * (int)sizeof(sljit_w)), DR(SLJIT_SAVED_EREG2))); + FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_EREG2) | IMM(local_size - 6 * (sljit_si)sizeof(sljit_sw)), DR(SLJIT_SAVED_EREG2))); if (compiler->saveds >= 4) - FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_EREG1) | IMM(local_size - 5 * (int)sizeof(sljit_w)), DR(SLJIT_SAVED_EREG1))); + FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_EREG1) | IMM(local_size - 5 * (sljit_si)sizeof(sljit_sw)), DR(SLJIT_SAVED_EREG1))); if (compiler->saveds >= 3) - FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_REG3) | IMM(local_size - 4 * (int)sizeof(sljit_w)), DR(SLJIT_SAVED_REG3))); + FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_REG3) | IMM(local_size - 4 * (sljit_si)sizeof(sljit_sw)), DR(SLJIT_SAVED_REG3))); if (compiler->saveds >= 2) - FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_REG2) | IMM(local_size - 3 * (int)sizeof(sljit_w)), DR(SLJIT_SAVED_REG2))); + FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_REG2) | IMM(local_size - 3 * (sljit_si)sizeof(sljit_sw)), DR(SLJIT_SAVED_REG2))); if (compiler->saveds >= 1) - FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_REG1) | IMM(local_size - 2 * (int)sizeof(sljit_w)), DR(SLJIT_SAVED_REG1))); + FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(SLJIT_SAVED_REG1) | IMM(local_size - 2 * (sljit_si)sizeof(sljit_sw)), DR(SLJIT_SAVED_REG1))); FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS)); if (compiler->local_size <= SIMM_MAX) @@ -569,57 +573,62 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, /* --------------------------------------------------------------------- */ #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) -#define ARCH_DEPEND(a, b) a +#define ARCH_32_64(a, b) a #else -#define ARCH_DEPEND(a, b) b +#define ARCH_32_64(a, b) b #endif -static SLJIT_CONST sljit_ins data_transfer_insts[16] = { -/* s u w */ ARCH_DEPEND(HI(43) /* sw */, HI(63) /* sd */), -/* s u b */ HI(40) /* sb */, -/* s u h */ HI(41) /* sh*/, -/* s u i */ HI(43) /* sw */, +static SLJIT_CONST sljit_ins data_transfer_insts[16 + 4] = { +/* u w s */ ARCH_32_64(HI(43) /* sw */, HI(63) /* sd */), +/* u w l */ ARCH_32_64(HI(35) /* lw */, HI(55) /* ld */), +/* u b s */ HI(40) /* sb */, +/* u b l */ HI(36) /* lbu */, +/* u h s */ HI(41) /* sh */, +/* u h l */ HI(37) /* lhu */, +/* u i s */ HI(43) /* sw */, +/* u i l */ ARCH_32_64(HI(35) /* lw */, HI(39) /* lwu */), -/* s s w */ ARCH_DEPEND(HI(43) /* sw */, HI(63) /* sd */), -/* s s b */ HI(40) /* sb */, -/* s s h */ HI(41) /* sh*/, -/* s s i */ HI(43) /* sw */, +/* s w s */ ARCH_32_64(HI(43) /* sw */, HI(63) /* sd */), +/* s w l */ ARCH_32_64(HI(35) /* lw */, HI(55) /* ld */), +/* s b s */ HI(40) /* sb */, +/* s b l */ HI(32) /* lb */, +/* s h s */ HI(41) /* sh */, +/* s h l */ HI(33) /* lh */, +/* s i s */ HI(43) /* sw */, +/* s i l */ HI(35) /* lw */, -/* l u w */ ARCH_DEPEND(HI(35) /* lw */, HI(55) /* ld */), -/* l u b */ HI(36) /* lbu */, -/* l u h */ HI(37) /* lhu */, -/* l u i */ ARCH_DEPEND(HI(35) /* lw */, HI(39) /* lwu */), - -/* l s w */ ARCH_DEPEND(HI(35) /* lw */, HI(55) /* ld */), -/* l s b */ HI(32) /* lb */, -/* l s h */ HI(33) /* lh */, -/* l s i */ HI(35) /* lw */, +/* d s */ HI(61) /* sdc1 */, +/* d l */ HI(53) /* ldc1 */, +/* s s */ HI(57) /* swc1 */, +/* s l */ HI(49) /* lwc1 */, }; +#undef ARCH_32_64 + /* reg_ar is an absoulute register! */ /* Can perform an operation using at most 1 instruction. */ -static int getput_arg_fast(struct sljit_compiler *compiler, int flags, int reg_ar, int arg, sljit_w argw) +static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg_ar, sljit_si arg, sljit_sw argw) { SLJIT_ASSERT(arg & SLJIT_MEM); - if (!(flags & WRITE_BACK) && !(arg & 0xf0) && argw <= SIMM_MAX && argw >= SIMM_MIN) { + if ((!(flags & WRITE_BACK) || !(arg & 0xf)) && !(arg & 0xf0) && argw <= SIMM_MAX && argw >= SIMM_MIN) { /* Works for both absoulte and relative addresses. */ if (SLJIT_UNLIKELY(flags & ARG_TEST)) return 1; - FAIL_IF(push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(arg & 0xf) | TA(reg_ar) | IMM(argw), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS)); + FAIL_IF(push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(arg & 0xf) + | TA(reg_ar) | IMM(argw), ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) ? reg_ar : MOVABLE_INS)); return -1; } - return (flags & ARG_TEST) ? SLJIT_SUCCESS : 0; + return 0; } /* See getput_arg below. Note: can_cache is called only for binary operators. Those operators always uses word arguments without write back. */ -static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw) +static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw) { - if (!(next_arg & SLJIT_MEM)) - return 0; + SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM)); /* Simple operation except for updates. */ if (arg & 0xf0) { @@ -631,7 +640,7 @@ static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw) } if (arg == next_arg) { - if (((sljit_uw)(next_argw - argw) <= SIMM_MAX && (sljit_uw)(next_argw - argw) >= SIMM_MIN)) + if (((next_argw - argw) <= SIMM_MAX && (next_argw - argw) >= SIMM_MIN)) return 1; return 0; } @@ -640,10 +649,9 @@ static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw) } /* Emit the necessary instructions. See can_cache above. */ -static int getput_arg(struct sljit_compiler *compiler, int flags, int reg_ar, int arg, sljit_w argw, int next_arg, sljit_w next_argw) +static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg_ar, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw) { - int tmp_ar; - int base; + sljit_si tmp_ar, base, delay_slot; SLJIT_ASSERT(arg & SLJIT_MEM); if (!(next_arg & SLJIT_MEM)) { @@ -651,7 +659,13 @@ static int getput_arg(struct sljit_compiler *compiler, int flags, int reg_ar, in next_argw = 0; } - tmp_ar = (flags & LOAD_DATA) ? reg_ar : DR(TMP_REG3); + if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) { + tmp_ar = reg_ar; + delay_slot = reg_ar; + } else { + tmp_ar = DR(TMP_REG1); + delay_slot = MOVABLE_INS; + } base = arg & 0xf; if (SLJIT_UNLIKELY(arg & 0xf0)) { @@ -666,22 +680,22 @@ static int getput_arg(struct sljit_compiler *compiler, int flags, int reg_ar, in if (argw == compiler->cache_argw) { if (!(flags & WRITE_BACK)) { if (arg == compiler->cache_arg) - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot); if ((SLJIT_MEM | (arg & 0xf0)) == compiler->cache_arg) { if (arg == next_arg && argw == (next_argw & 0x3)) { compiler->cache_arg = arg; compiler->cache_argw = argw; FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | D(TMP_REG3), DR(TMP_REG3))); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot); } FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | DA(tmp_ar), tmp_ar)); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot); } } else { if ((SLJIT_MEM | (arg & 0xf0)) == compiler->cache_arg) { FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | D(base), DR(base))); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar), delay_slot); } } } @@ -701,10 +715,10 @@ static int getput_arg(struct sljit_compiler *compiler, int flags, int reg_ar, in } else FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? ((arg >> 4) & 0xf) : TMP_REG3) | DA(tmp_ar), tmp_ar)); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot); } FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? ((arg >> 4) & 0xf) : TMP_REG3) | D(base), DR(base))); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar), delay_slot); } if (SLJIT_UNLIKELY(flags & WRITE_BACK) && base) { @@ -740,7 +754,7 @@ static int getput_arg(struct sljit_compiler *compiler, int flags, int reg_ar, in FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | D(base), DR(base))); } } - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(base) | TA(reg_ar), delay_slot); } if (compiler->cache_arg == arg && argw - compiler->cache_argw <= SIMM_MAX && argw - compiler->cache_argw >= SIMM_MIN) { @@ -748,7 +762,7 @@ static int getput_arg(struct sljit_compiler *compiler, int flags, int reg_ar, in FAIL_IF(push_inst(compiler, ADDIU_W | S(TMP_REG3) | T(TMP_REG3) | IMM(argw - compiler->cache_argw), DR(TMP_REG3))); compiler->cache_argw = argw; } - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot); } if (compiler->cache_arg == SLJIT_MEM && argw - compiler->cache_argw <= SIMM_MAX && argw - compiler->cache_argw >= SIMM_MIN) { @@ -762,19 +776,19 @@ static int getput_arg(struct sljit_compiler *compiler, int flags, int reg_ar, in compiler->cache_argw = argw; if (!base) - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot); if (arg == next_arg && next_argw - argw <= SIMM_MAX && next_argw - argw >= SIMM_MIN) { compiler->cache_arg = arg; FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | T(base) | D(TMP_REG3), DR(TMP_REG3))); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot); } FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | T(base) | DA(tmp_ar), tmp_ar)); - return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), (flags & LOAD_DATA) ? reg_ar : MOVABLE_INS); + return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot); } -static SLJIT_INLINE int emit_op_mem(struct sljit_compiler *compiler, int flags, int reg_ar, int arg, sljit_w argw) +static SLJIT_INLINE sljit_si emit_op_mem(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg_ar, sljit_si arg, sljit_sw argw) { if (getput_arg_fast(compiler, flags, reg_ar, arg, argw)) return compiler->error; @@ -783,35 +797,44 @@ static SLJIT_INLINE int emit_op_mem(struct sljit_compiler *compiler, int flags, return getput_arg(compiler, flags, reg_ar, arg, argw, 0, 0); } -static int emit_op(struct sljit_compiler *compiler, int op, int flags, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w) +{ + if (getput_arg_fast(compiler, flags, reg, arg1, arg1w)) + return compiler->error; + return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w); +} + +static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags, + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { /* arg1 goes to TMP_REG1 or src reg arg2 goes to TMP_REG2, imm or src reg TMP_REG3 can be used for caching result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */ - int dst_r = TMP_REG2; - int src1_r; - sljit_w src2_r = 0; - int sugg_src2_r = TMP_REG2; + sljit_si dst_r = TMP_REG2; + sljit_si src1_r; + sljit_sw src2_r = 0; + sljit_si sugg_src2_r = TMP_REG2; - compiler->cache_arg = 0; - compiler->cache_argw = 0; - - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REG3) { - dst_r = dst; - flags |= REG_DEST; - if (GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOVU_SI) - sugg_src2_r = dst_r; + if (!(flags & ALT_KEEP_CACHE)) { + compiler->cache_arg = 0; + compiler->cache_argw = 0; } - else if (dst == SLJIT_UNUSED) { + + if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) { if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM)) return SLJIT_SUCCESS; if (GET_FLAGS(op)) flags |= UNUSED_DEST; } + else if (dst <= TMP_REG3) { + dst_r = dst; + flags |= REG_DEST; + if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) + sugg_src2_r = dst_r; + } else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, DR(TMP_REG1), dst, dstw)) flags |= SLOW_DEST; @@ -823,7 +846,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int flags, src2_r = src2w; } } - if ((src1 & SLJIT_IMM) && src1w && (flags & CUMULATIVE_OP) && !(flags & SRC2_IMM)) { + if (!(flags & SRC2_IMM) && (flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w) { if ((!(flags & LOGICAL_OP) && (src1w <= SIMM_MAX && src1w >= SIMM_MIN)) || ((flags & LOGICAL_OP) && !(src1w & ~UIMM_MAX))) { flags |= SRC2_IMM; @@ -839,7 +862,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int flags, } /* Source 1. */ - if (src1 >= SLJIT_TEMPORARY_REG1 && src1 <= TMP_REG3) { + if (src1 <= TMP_REG3) { src1_r = src1; flags |= REG1_SOURCE; } @@ -860,20 +883,23 @@ static int emit_op(struct sljit_compiler *compiler, int op, int flags, } /* Source 2. */ - if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= TMP_REG3) { + if (src2 <= TMP_REG3) { src2_r = src2; flags |= REG2_SOURCE; - if (!(flags & REG_DEST) && GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOVU_SI) + if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) dst_r = src2_r; } else if (src2 & SLJIT_IMM) { if (!(flags & SRC2_IMM)) { - if (src2w || (GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOVU_SI)) { + if (src2w) { FAIL_IF(load_immediate(compiler, DR(sugg_src2_r), src2w)); src2_r = sugg_src2_r; } - else + else { src2_r = 0; + if ((op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) && (dst & SLJIT_MEM)) + dst_r = 0; + } } } else { @@ -913,7 +939,7 @@ static int emit_op(struct sljit_compiler *compiler, int op, int flags, return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) { CHECK_ERROR(); check_sljit_emit_op0(compiler, op); @@ -926,29 +952,29 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int return push_inst(compiler, NOP, UNMOVABLE_INS); case SLJIT_UMUL: case SLJIT_SMUL: - FAIL_IF(push_inst(compiler, (op == SLJIT_UMUL ? MULTU : MULT) | S(SLJIT_TEMPORARY_REG1) | T(SLJIT_TEMPORARY_REG2), MOVABLE_INS)); - FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_TEMPORARY_REG1), DR(SLJIT_TEMPORARY_REG1))); - return push_inst(compiler, MFHI | D(SLJIT_TEMPORARY_REG2), DR(SLJIT_TEMPORARY_REG2)); + FAIL_IF(push_inst(compiler, (op == SLJIT_UMUL ? MULTU : MULT) | S(SLJIT_SCRATCH_REG1) | T(SLJIT_SCRATCH_REG2), MOVABLE_INS)); + FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_SCRATCH_REG1), DR(SLJIT_SCRATCH_REG1))); + return push_inst(compiler, MFHI | D(SLJIT_SCRATCH_REG2), DR(SLJIT_SCRATCH_REG2)); case SLJIT_UDIV: case SLJIT_SDIV: #if !(defined SLJIT_MIPS_32_64 && SLJIT_MIPS_32_64) FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); #endif - FAIL_IF(push_inst(compiler, (op == SLJIT_UDIV ? DIVU : DIV) | S(SLJIT_TEMPORARY_REG1) | T(SLJIT_TEMPORARY_REG2), MOVABLE_INS)); - FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_TEMPORARY_REG1), DR(SLJIT_TEMPORARY_REG1))); - return push_inst(compiler, MFHI | D(SLJIT_TEMPORARY_REG2), DR(SLJIT_TEMPORARY_REG2)); + FAIL_IF(push_inst(compiler, (op == SLJIT_UDIV ? DIVU : DIV) | S(SLJIT_SCRATCH_REG1) | T(SLJIT_SCRATCH_REG2), MOVABLE_INS)); + FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_SCRATCH_REG1), DR(SLJIT_SCRATCH_REG1))); + return push_inst(compiler, MFHI | D(SLJIT_SCRATCH_REG2), DR(SLJIT_SCRATCH_REG2)); } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +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) { #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - #define inp_flags 0 +# define flags 0 #endif CHECK_ERROR(); @@ -956,74 +982,74 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int ADJUST_LOCAL_OFFSET(dst, dstw); ADJUST_LOCAL_OFFSET(src, srcw); - SLJIT_COMPILE_ASSERT(SLJIT_MOV + 7 == SLJIT_MOVU, movu_offset); - switch (GET_OPCODE(op)) { case SLJIT_MOV: - return emit_op(compiler, SLJIT_MOV, inp_flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + case SLJIT_MOV_P: + return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_MOV_UI: - return emit_op(compiler, SLJIT_MOV_UI, inp_flags | INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_MOV_UI, flags | INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_MOV_SI: - return emit_op(compiler, SLJIT_MOV_SI, inp_flags | INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_MOV_SI, flags | INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_MOV_UB: - return emit_op(compiler, SLJIT_MOV_UB, inp_flags | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_UB, flags | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw); case SLJIT_MOV_SB: - return emit_op(compiler, SLJIT_MOV_SB, inp_flags | BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_SB, flags | BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw); case SLJIT_MOV_UH: - return emit_op(compiler, SLJIT_MOV_UH, inp_flags | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_UH, flags | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw); case SLJIT_MOV_SH: - return emit_op(compiler, SLJIT_MOV_SH, inp_flags | HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_SH, flags | HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw); case SLJIT_MOVU: - return emit_op(compiler, SLJIT_MOV, inp_flags | WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); + case SLJIT_MOVU_P: + return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_MOVU_UI: - return emit_op(compiler, SLJIT_MOV_UI, inp_flags | INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_MOV_UI, flags | INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_MOVU_SI: - return emit_op(compiler, SLJIT_MOV_SI, inp_flags | INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_MOV_SI, flags | INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_MOVU_UB: - return emit_op(compiler, SLJIT_MOV_UB, inp_flags | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_UB, flags | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_ub)srcw : srcw); case SLJIT_MOVU_SB: - return emit_op(compiler, SLJIT_MOV_SB, inp_flags | BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_SB, flags | BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sb)srcw : srcw); case SLJIT_MOVU_UH: - return emit_op(compiler, SLJIT_MOV_UH, inp_flags | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_UH, flags | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_uh)srcw : srcw); case SLJIT_MOVU_SH: - return emit_op(compiler, SLJIT_MOV_SH, inp_flags | HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw); + return emit_op(compiler, SLJIT_MOV_SH, flags | HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_sh)srcw : srcw); case SLJIT_NOT: - return emit_op(compiler, op, inp_flags, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_NEG: - return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), inp_flags | IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw); + return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), flags | IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw); case SLJIT_CLZ: - return emit_op(compiler, op, inp_flags, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw); } return SLJIT_SUCCESS; #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - #undef inp_flags +# undef flags #endif } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +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) { #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - #define inp_flags 0 +# define flags 0 #endif CHECK_ERROR(); @@ -1035,19 +1061,19 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int switch (GET_OPCODE(op)) { case SLJIT_ADD: case SLJIT_ADDC: - return emit_op(compiler, op, inp_flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w); case SLJIT_SUB: case SLJIT_SUBC: - return emit_op(compiler, op, inp_flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w); case SLJIT_MUL: - return emit_op(compiler, op, inp_flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w); case SLJIT_AND: case SLJIT_OR: case SLJIT_XOR: - return emit_op(compiler, op, inp_flags | CUMULATIVE_OP | LOGICAL_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, op, flags | CUMULATIVE_OP | LOGICAL_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w); case SLJIT_SHL: case SLJIT_LSHR: @@ -1056,26 +1082,31 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int if (src2 & SLJIT_IMM) src2w &= 0x1f; #else - if (src2 & SLJIT_IMM) - src2w &= 0x3f; + SLJIT_ASSERT_STOP(); #endif - return emit_op(compiler, op, inp_flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w); } return SLJIT_SUCCESS; #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) - #undef inp_flags +# undef flags #endif } -SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg) { check_sljit_get_register_index(reg); return reg_map[reg]; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, int size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg) +{ + check_sljit_get_float_register_index(reg); + return reg << 1; +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, + void *instruction, sljit_si size) { CHECK_ERROR(); check_sljit_emit_op_custom(compiler, instruction, size); @@ -1088,13 +1119,13 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compile /* Floating point operators */ /* --------------------------------------------------------------------- */ -SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void) { #if (defined SLJIT_QEMU && SLJIT_QEMU) /* Qemu says fir is 0 by default. */ return 1; #elif defined(__GNUC__) - sljit_w fir; + sljit_sw fir; asm ("cfc1 %0, $0" : "=r"(fir)); return (fir >> 22) & 0x1; #else @@ -1102,119 +1133,95 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) #endif } -static int emit_fpu_data_transfer(struct sljit_compiler *compiler, int fpu_reg, int load, int arg, sljit_w argw) +#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_SINGLE_OP) >> 7)) +#define FMT(op) (((op & SLJIT_SINGLE_OP) ^ SLJIT_SINGLE_OP) << (21 - 8)) + +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - int hi_reg; - - SLJIT_ASSERT(arg & SLJIT_MEM); - - /* Fast loads and stores. */ - if (!(arg & 0xf0)) { - /* Both for (arg & 0xf) == SLJIT_UNUSED and (arg & 0xf) != SLJIT_UNUSED. */ - if (argw <= SIMM_MAX && argw >= SIMM_MIN) - return push_inst(compiler, (load ? LDC1 : SDC1) | S(arg & 0xf) | FT(fpu_reg) | IMM(argw), MOVABLE_INS); - } - - if (arg & 0xf0) { - argw &= 0x3; - hi_reg = (arg >> 4) & 0xf; - if (argw) { - FAIL_IF(push_inst(compiler, SLL_W | T(hi_reg) | D(TMP_REG1) | SH_IMM(argw), DR(TMP_REG1))); - hi_reg = TMP_REG1; - } - FAIL_IF(push_inst(compiler, ADDU_W | S(hi_reg) | T(arg & 0xf) | D(TMP_REG1), DR(TMP_REG1))); - return push_inst(compiler, (load ? LDC1 : SDC1) | S(TMP_REG1) | FT(fpu_reg) | IMM(0), MOVABLE_INS); - } - - /* Use cache. */ - if (compiler->cache_arg == arg && argw - compiler->cache_argw <= SIMM_MAX && argw - compiler->cache_argw >= SIMM_MIN) - return push_inst(compiler, (load ? LDC1 : SDC1) | S(TMP_REG3) | FT(fpu_reg) | IMM(argw - compiler->cache_argw), MOVABLE_INS); - - /* Put value to cache. */ - compiler->cache_arg = arg; - compiler->cache_argw = argw; - - FAIL_IF(load_immediate(compiler, DR(TMP_REG3), argw)); - if (arg & 0xf) - FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | T(arg & 0xf) | D(TMP_REG3), DR(TMP_REG3))); - return push_inst(compiler, (load ? LDC1 : SDC1) | S(TMP_REG3) | FT(fpu_reg) | IMM(0), MOVABLE_INS); -} - -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) -{ - int dst_fr; + sljit_si dst_fr; CHECK_ERROR(); check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw); + SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error); compiler->cache_arg = 0; compiler->cache_argw = 0; - if (GET_OPCODE(op) == SLJIT_FCMP) { - if (dst > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 1, dst, dstw)); + if (GET_OPCODE(op) == SLJIT_CMPD) { + if (dst > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, dst, dstw, src, srcw)); dst = TMP_FREG1; } - if (src > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG2, 1, src, srcw)); + else + dst <<= 1; + + if (src > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src, srcw, 0, 0)); src = TMP_FREG2; } + else + src <<= 1; /* src and dst are swapped. */ if (op & SLJIT_SET_E) { - FAIL_IF(push_inst(compiler, C_UEQ_D | FT(src) | FS(dst), UNMOVABLE_INS)); + FAIL_IF(push_inst(compiler, C_UEQ_fmt | FMT(op) | FT(src) | FS(dst), UNMOVABLE_INS)); FAIL_IF(push_inst(compiler, CFC1 | TA(EQUAL_FLAG) | DA(FCSR_REG), EQUAL_FLAG)); FAIL_IF(push_inst(compiler, SRL | TA(EQUAL_FLAG) | DA(EQUAL_FLAG) | SH_IMM(23), EQUAL_FLAG)); FAIL_IF(push_inst(compiler, ANDI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG)); } if (op & SLJIT_SET_S) { /* Mixing the instructions for the two checks. */ - FAIL_IF(push_inst(compiler, C_ULT_D | FT(src) | FS(dst), UNMOVABLE_INS)); + FAIL_IF(push_inst(compiler, C_ULT_fmt | FMT(op) | FT(src) | FS(dst), UNMOVABLE_INS)); FAIL_IF(push_inst(compiler, CFC1 | TA(ULESS_FLAG) | DA(FCSR_REG), ULESS_FLAG)); - FAIL_IF(push_inst(compiler, C_ULT_D | FT(dst) | FS(src), UNMOVABLE_INS)); + FAIL_IF(push_inst(compiler, C_ULT_fmt | FMT(op) | FT(dst) | FS(src), UNMOVABLE_INS)); FAIL_IF(push_inst(compiler, SRL | TA(ULESS_FLAG) | DA(ULESS_FLAG) | SH_IMM(23), ULESS_FLAG)); FAIL_IF(push_inst(compiler, ANDI | SA(ULESS_FLAG) | TA(ULESS_FLAG) | IMM(1), ULESS_FLAG)); FAIL_IF(push_inst(compiler, CFC1 | TA(UGREATER_FLAG) | DA(FCSR_REG), UGREATER_FLAG)); FAIL_IF(push_inst(compiler, SRL | TA(UGREATER_FLAG) | DA(UGREATER_FLAG) | SH_IMM(23), UGREATER_FLAG)); FAIL_IF(push_inst(compiler, ANDI | SA(UGREATER_FLAG) | TA(UGREATER_FLAG) | IMM(1), UGREATER_FLAG)); } - return push_inst(compiler, C_UN_D | FT(src) | FS(dst), FCSR_FCC); + return push_inst(compiler, C_UN_fmt | FMT(op) | FT(src) | FS(dst), FCSR_FCC); } - dst_fr = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG1 : dst; + dst_fr = (dst > SLJIT_FLOAT_REG6) ? TMP_FREG1 : (dst << 1); - if (src > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, dst_fr, 1, src, srcw)); + if (src > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_fr, src, srcw, dst, dstw)); src = dst_fr; } + else + src <<= 1; - switch (op) { - case SLJIT_FMOV: + switch (GET_OPCODE(op)) { + case SLJIT_MOVD: if (src != dst_fr && dst_fr != TMP_FREG1) - FAIL_IF(push_inst(compiler, MOV_D | FS(src) | FD(dst_fr), MOVABLE_INS)); + FAIL_IF(push_inst(compiler, MOV_fmt | FMT(op) | FS(src) | FD(dst_fr), MOVABLE_INS)); break; - case SLJIT_FNEG: - FAIL_IF(push_inst(compiler, NEG_D | FS(src) | FD(dst_fr), MOVABLE_INS)); + case SLJIT_NEGD: + FAIL_IF(push_inst(compiler, NEG_fmt | FMT(op) | FS(src) | FD(dst_fr), MOVABLE_INS)); break; - case SLJIT_FABS: - FAIL_IF(push_inst(compiler, ABS_D | FS(src) | FD(dst_fr), MOVABLE_INS)); + case SLJIT_ABSD: + FAIL_IF(push_inst(compiler, ABS_fmt | FMT(op) | FS(src) | FD(dst_fr), MOVABLE_INS)); break; } - if (dst_fr == TMP_FREG1) - FAIL_IF(emit_fpu_data_transfer(compiler, src, 0, dst, dstw)); + if (dst_fr == TMP_FREG1) { + if (GET_OPCODE(op) == SLJIT_MOVD) + dst_fr = src; + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), dst_fr, dst, dstw, 0, 0)); + } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(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) { - int dst_fr; + sljit_si dst_fr, flags = 0; CHECK_ERROR(); check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w); @@ -1222,38 +1229,68 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, in compiler->cache_arg = 0; compiler->cache_argw = 0; - dst_fr = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG1 : dst; + dst_fr = (dst > SLJIT_FLOAT_REG6) ? TMP_FREG2 : (dst << 1); - if (src2 > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG2, 1, src2, src2w)); - src2 = TMP_FREG2; + if (src1 > SLJIT_FLOAT_REG6) { + if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w)) { + FAIL_IF(compiler->error); + src1 = TMP_FREG1; + } else + flags |= SLOW_SRC1; } + else + src1 <<= 1; - if (src1 > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 1, src1, src1w)); + if (src2 > SLJIT_FLOAT_REG6) { + if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w)) { + FAIL_IF(compiler->error); + src2 = TMP_FREG2; + } else + flags |= SLOW_SRC2; + } + else + src2 <<= 1; + + if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) { + if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, src1, src1w)); + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw)); + } + else { + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w)); + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw)); + } + } + else if (flags & SLOW_SRC1) + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw)); + else if (flags & SLOW_SRC2) + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw)); + + if (flags & SLOW_SRC1) src1 = TMP_FREG1; - } + if (flags & SLOW_SRC2) + src2 = TMP_FREG2; - switch (op) { - case SLJIT_FADD: - FAIL_IF(push_inst(compiler, ADD_D | FT(src2) | FS(src1) | FD(dst_fr), MOVABLE_INS)); + switch (GET_OPCODE(op)) { + case SLJIT_ADDD: + FAIL_IF(push_inst(compiler, ADD_fmt | FMT(op) | FT(src2) | FS(src1) | FD(dst_fr), MOVABLE_INS)); break; - case SLJIT_FSUB: - FAIL_IF(push_inst(compiler, SUB_D | FT(src2) | FS(src1) | FD(dst_fr), MOVABLE_INS)); + case SLJIT_SUBD: + FAIL_IF(push_inst(compiler, SUB_fmt | FMT(op) | FT(src2) | FS(src1) | FD(dst_fr), MOVABLE_INS)); break; - case SLJIT_FMUL: - FAIL_IF(push_inst(compiler, MUL_D | FT(src2) | FS(src1) | FD(dst_fr), MOVABLE_INS)); + case SLJIT_MULD: + FAIL_IF(push_inst(compiler, MUL_fmt | FMT(op) | FT(src2) | FS(src1) | FD(dst_fr), MOVABLE_INS)); break; - case SLJIT_FDIV: - FAIL_IF(push_inst(compiler, DIV_D | FT(src2) | FS(src1) | FD(dst_fr), MOVABLE_INS)); + case SLJIT_DIVD: + FAIL_IF(push_inst(compiler, DIV_fmt | FMT(op) | FT(src2) | FS(src1) | FD(dst_fr), MOVABLE_INS)); break; } - if (dst_fr == TMP_FREG1) - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 0, dst, dstw)); + if (dst_fr == TMP_FREG2) + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0)); return SLJIT_SUCCESS; } @@ -1262,26 +1299,30 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, in /* Other instructions */ /* --------------------------------------------------------------------- */ -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw) +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); ADJUST_LOCAL_OFFSET(dst, dstw); - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) + /* For UNUSED dst. Uncommon, but possible. */ + if (dst == SLJIT_UNUSED) + return SLJIT_SUCCESS; + + if (dst <= TMP_REG3) return push_inst(compiler, ADDU_W | SA(RETURN_ADDR_REG) | TA(0) | D(dst), DR(dst)); - else if (dst & SLJIT_MEM) - return emit_op_mem(compiler, WORD_DATA, RETURN_ADDR_REG, dst, dstw); - return SLJIT_SUCCESS; + + /* Memory. */ + return emit_op_mem(compiler, WORD_DATA, RETURN_ADDR_REG, dst, dstw); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw) +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); ADJUST_LOCAL_OFFSET(src, srcw); - if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) + if (src <= TMP_REG3) FAIL_IF(push_inst(compiler, ADDU_W | S(src) | TA(0) | DA(RETURN_ADDR_REG), RETURN_ADDR_REG)); else if (src & SLJIT_MEM) FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG, src, srcw)); @@ -1316,7 +1357,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi #if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) #define JUMP_LENGTH 4 #else -#define JUMP_LENGTH 7 +#error "Implementation required" #endif #define BR_Z(src) \ @@ -1339,12 +1380,12 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi flags = IS_BIT16_COND; \ delay_check = FCSR_FCC; -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, int type) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type) { struct sljit_jump *jump; sljit_ins inst; - int flags = 0; - int delay_check = UNMOVABLE_INS; + sljit_si flags = 0; + sljit_si delay_check = UNMOVABLE_INS; CHECK_ERROR_PTR(); check_sljit_emit_jump(compiler, type); @@ -1399,10 +1440,10 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile case SLJIT_C_MUL_NOT_OVERFLOW: BR_NZ(OVERFLOW_FLAG); break; - case SLJIT_C_FLOAT_NAN: + case SLJIT_C_FLOAT_UNORDERED: BR_F(); break; - case SLJIT_C_FLOAT_NOT_NAN: + case SLJIT_C_FLOAT_ORDERED: BR_T(); break; default: @@ -1430,7 +1471,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile PTR_FAIL_IF(push_inst(compiler, JALR | S(TMP_REG2) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); jump->addr = compiler->size; /* A NOP if type < CALL1. */ - PTR_FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_TEMPORARY_REG1) | TA(0) | DA(4), UNMOVABLE_INS)); + PTR_FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SCRATCH_REG1) | TA(0) | DA(4), UNMOVABLE_INS)); } return jump; } @@ -1455,12 +1496,12 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile src2 = 0; \ } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, int type, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_si type, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { struct sljit_jump *jump; - int flags; + sljit_si flags; sljit_ins inst; CHECK_ERROR_PTR(); @@ -1472,17 +1513,11 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler compiler->cache_argw = 0; flags = ((type & SLJIT_INT_OP) ? INT_DATA : WORD_DATA) | LOAD_DATA; if (src1 & SLJIT_MEM) { - if (getput_arg_fast(compiler, flags, DR(TMP_REG1), src1, src1w)) - PTR_FAIL_IF(compiler->error); - else - PTR_FAIL_IF(getput_arg(compiler, flags, DR(TMP_REG1), src1, src1w, src2, src2w)); + PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(TMP_REG1), src1, src1w, src2, src2w)); src1 = TMP_REG1; } if (src2 & SLJIT_MEM) { - if (getput_arg_fast(compiler, flags, DR(TMP_REG2), src2, src2w)) - PTR_FAIL_IF(compiler->error); - else - PTR_FAIL_IF(getput_arg(compiler, flags, DR(TMP_REG2), src2, src2w, 0, 0)); + PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(TMP_REG2), src2, src2w, 0, 0)); src2 = TMP_REG2; } @@ -1582,13 +1617,13 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler #undef RESOLVE_IMM1 #undef RESOLVE_IMM2 -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, int type, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_si type, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { struct sljit_jump *jump; sljit_ins inst; - int if_true; + sljit_si if_true; CHECK_ERROR_PTR(); check_sljit_emit_fcmp(compiler, type, src1, src1w, src2, src2w); @@ -1596,58 +1631,62 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compile compiler->cache_arg = 0; compiler->cache_argw = 0; - if (src1 > SLJIT_FLOAT_REG4) { - PTR_FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 1, src1, src1w)); + if (src1 > SLJIT_FLOAT_REG6) { + PTR_FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(type) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w)); src1 = TMP_FREG1; } - if (src2 > SLJIT_FLOAT_REG4) { - PTR_FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG2, 1, src2, src2w)); + else + src1 <<= 1; + + if (src2 > SLJIT_FLOAT_REG6) { + PTR_FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(type) | LOAD_DATA, TMP_FREG2, src2, src2w, 0, 0)); src2 = TMP_FREG2; } + else + src2 <<= 1; jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); PTR_FAIL_IF(!jump); set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP); jump->flags |= IS_BIT16_COND; - type &= 0xff; - switch (type) { + switch (type & 0xff) { case SLJIT_C_FLOAT_EQUAL: - inst = C_UEQ_D; + inst = C_UEQ_fmt; if_true = 1; break; case SLJIT_C_FLOAT_NOT_EQUAL: - inst = C_UEQ_D; + inst = C_UEQ_fmt; if_true = 0; break; case SLJIT_C_FLOAT_LESS: - inst = C_ULT_D; + inst = C_ULT_fmt; if_true = 1; break; case SLJIT_C_FLOAT_GREATER_EQUAL: - inst = C_ULT_D; + inst = C_ULT_fmt; if_true = 0; break; case SLJIT_C_FLOAT_GREATER: - inst = C_ULE_D; + inst = C_ULE_fmt; if_true = 0; break; case SLJIT_C_FLOAT_LESS_EQUAL: - inst = C_ULE_D; + inst = C_ULE_fmt; if_true = 1; break; - case SLJIT_C_FLOAT_NAN: - inst = C_UN_D; + case SLJIT_C_FLOAT_UNORDERED: + inst = C_UN_fmt; if_true = 1; break; - case SLJIT_C_FLOAT_NOT_NAN: + case SLJIT_C_FLOAT_ORDERED: default: /* Make compilers happy. */ - inst = C_UN_D; + inst = C_UN_fmt; if_true = 0; break; } - PTR_FAIL_IF(push_inst(compiler, inst | FT(src2) | FS(src1), UNMOVABLE_INS)); + PTR_FAIL_IF(push_inst(compiler, inst | FMT(type) | FT(src2) | FS(src1), UNMOVABLE_INS)); /* Intentionally the other opcode. */ PTR_FAIL_IF(push_inst(compiler, (if_true ? BC1F : BC1T) | JUMP_LENGTH, UNMOVABLE_INS)); PTR_FAIL_IF(emit_const(compiler, TMP_REG2, 0)); @@ -1663,16 +1702,19 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compile #undef BR_T #undef BR_F -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, int type, int src, sljit_w srcw) +#undef FLOAT_DATA +#undef FMT + +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw) { - int src_r = TMP_REG2; + sljit_si src_r = TMP_REG2; struct sljit_jump *jump = NULL; CHECK_ERROR(); check_sljit_emit_ijump(compiler, type, src, srcw); ADJUST_LOCAL_OFFSET(src, srcw); - if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) { + if (src <= TMP_REG3) { if (DR(src) != 4) src_r = src; else @@ -1690,12 +1732,12 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i } FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); /* We need an extra instruction in any case. */ - return push_inst(compiler, ADDU_W | S(SLJIT_TEMPORARY_REG1) | TA(0) | DA(4), UNMOVABLE_INS); + return push_inst(compiler, ADDU_W | S(SLJIT_SCRATCH_REG1) | TA(0) | DA(4), UNMOVABLE_INS); } /* Register input. */ if (type >= SLJIT_CALL1) - FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_TEMPORARY_REG1) | TA(0) | DA(4), 4)); + FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SCRATCH_REG1) | TA(0) | DA(4), 4)); FAIL_IF(push_inst(compiler, JALR | S(src_r) | DA(RETURN_ADDR_REG), UNMOVABLE_INS)); return push_inst(compiler, ADDU_W | S(src_r) | TA(0) | D(PIC_ADDR_REG), UNMOVABLE_INS); } @@ -1721,18 +1763,32 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compiler, int op, int dst, sljit_w dstw, int type) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw, + sljit_si type) { - int sugg_dst_ar, dst_ar; + sljit_si sugg_dst_ar, dst_ar; + sljit_si flags = GET_ALL_FLAGS(op); CHECK_ERROR(); - check_sljit_emit_cond_value(compiler, op, dst, dstw, type); + check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type); ADJUST_LOCAL_OFFSET(dst, dstw); if (dst == SLJIT_UNUSED) return SLJIT_SUCCESS; - sugg_dst_ar = DR((op == SLJIT_MOV && dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2); + op = GET_OPCODE(op); + sugg_dst_ar = DR((op < SLJIT_ADD && dst <= TMP_REG3) ? dst : TMP_REG2); + + compiler->cache_arg = 0; + 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, DR(TMP_REG1), src, srcw, dst, dstw)); + src = TMP_REG1; + srcw = 0; + } switch (type) { case SLJIT_C_EQUAL: @@ -1775,8 +1831,8 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compil dst_ar = EQUAL_FLAG; break; - case SLJIT_C_FLOAT_NAN: - case SLJIT_C_FLOAT_NOT_NAN: + case SLJIT_C_FLOAT_UNORDERED: + case SLJIT_C_FLOAT_ORDERED: FAIL_IF(push_inst(compiler, CFC1 | TA(sugg_dst_ar) | DA(FCSR_REG), sugg_dst_ar)); FAIL_IF(push_inst(compiler, SRL | TA(sugg_dst_ar) | DA(sugg_dst_ar) | SH_IMM(23), sugg_dst_ar)); FAIL_IF(push_inst(compiler, ANDI | SA(sugg_dst_ar) | TA(sugg_dst_ar) | IMM(1), sugg_dst_ar)); @@ -1794,10 +1850,10 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compil dst_ar = sugg_dst_ar; } - if (GET_OPCODE(op) == SLJIT_OR) { + if (op >= SLJIT_ADD) { if (DR(TMP_REG2) != dst_ar) FAIL_IF(push_inst(compiler, ADDU_W | SA(dst_ar) | TA(0) | D(TMP_REG2), DR(TMP_REG2))); - return emit_op(compiler, op, CUMULATIVE_OP | LOGICAL_OP | IMM_OP, dst, dstw, dst, dstw, TMP_REG2, 0); + return emit_op(compiler, op | flags, CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0); } if (dst & SLJIT_MEM) @@ -1808,10 +1864,10 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compil return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w init_value) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value) { struct sljit_const *const_; - int reg; + sljit_si reg; CHECK_ERROR_PTR(); check_sljit_emit_const(compiler, dst, dstw, init_value); @@ -1821,7 +1877,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi PTR_FAIL_IF(!const_); set_const(const_, compiler); - reg = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2; + reg = (dst <= TMP_REG3) ? dst : TMP_REG2; PTR_FAIL_IF(emit_const(compiler, reg, init_value)); diff --git a/src/3rd/pcre/sjppc32.c b/src/3rd/pcre/sjppc32.c index 82d0508ac1..0bd35a6e0e 100644 --- a/src/3rd/pcre/sjppc32.c +++ b/src/3rd/pcre/sjppc32.c @@ -26,7 +26,7 @@ /* ppc 32-bit arch dependent functions. */ -static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w imm) +static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm) { if (imm <= SIMM_MAX && imm >= SIMM_MIN) return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm)); @@ -41,10 +41,59 @@ static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w imm) #define INS_CLEAR_LEFT(dst, src, from) \ (RLWINM | S(src) | A(dst) | ((from) << 6) | (31 << 1)) -static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags, - int dst, int src1, int src2) +static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags, + sljit_si dst, sljit_si src1, sljit_si src2) { switch (op) { + case SLJIT_MOV: + case SLJIT_MOV_UI: + case SLJIT_MOV_SI: + case SLJIT_MOV_P: + SLJIT_ASSERT(src1 == TMP_REG1); + if (dst != src2) + return push_inst(compiler, OR | S(src2) | A(dst) | B(src2)); + return SLJIT_SUCCESS; + + case SLJIT_MOV_UB: + case SLJIT_MOV_SB: + SLJIT_ASSERT(src1 == TMP_REG1); + if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { + if (op == SLJIT_MOV_SB) + return push_inst(compiler, EXTSB | S(src2) | A(dst)); + return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24)); + } + else if ((flags & REG_DEST) && op == SLJIT_MOV_SB) + return push_inst(compiler, EXTSB | S(src2) | A(dst)); + else { + SLJIT_ASSERT(dst == src2); + } + return SLJIT_SUCCESS; + + case SLJIT_MOV_UH: + case SLJIT_MOV_SH: + SLJIT_ASSERT(src1 == TMP_REG1); + if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { + if (op == SLJIT_MOV_SH) + return push_inst(compiler, EXTSH | S(src2) | A(dst)); + return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16)); + } + else { + SLJIT_ASSERT(dst == src2); + } + return SLJIT_SUCCESS; + + case SLJIT_NOT: + SLJIT_ASSERT(src1 == TMP_REG1); + return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2)); + + case SLJIT_NEG: + SLJIT_ASSERT(src1 == TMP_REG1); + return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2)); + + case SLJIT_CLZ: + SLJIT_ASSERT(src1 == TMP_REG1); + return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst)); + case SLJIT_ADD: if (flags & ALT_FORM1) { /* Flags does not set: BIN_IMM_EXTS unnecessary. */ @@ -71,7 +120,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, case SLJIT_ADDC: if (flags & ALT_FORM1) { - FAIL_IF(push_inst(compiler, MFXER | S(0))); + FAIL_IF(push_inst(compiler, MFXER | D(0))); FAIL_IF(push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2))); return push_inst(compiler, MTXER | S(0)); } @@ -106,7 +155,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, case SLJIT_SUBC: if (flags & ALT_FORM1) { - FAIL_IF(push_inst(compiler, MFXER | S(0))); + FAIL_IF(push_inst(compiler, MFXER | D(0))); FAIL_IF(push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1))); return push_inst(compiler, MTXER | S(0)); } @@ -179,65 +228,23 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2)); case SLJIT_ASHR: + if (flags & ALT_FORM3) + FAIL_IF(push_inst(compiler, MFXER | D(0))); if (flags & ALT_FORM1) { SLJIT_ASSERT(src2 == TMP_REG2); compiler->imm &= 0x1f; - return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11)); + FAIL_IF(push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11))); } - return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_MOV: - case SLJIT_MOV_UI: - case SLJIT_MOV_SI: - SLJIT_ASSERT(src1 == TMP_REG1); - if (dst != src2) - return push_inst(compiler, OR | S(src2) | A(dst) | B(src2)); - return SLJIT_SUCCESS; - - case SLJIT_MOV_UB: - case SLJIT_MOV_SB: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_SB) - return push_inst(compiler, EXTSB | S(src2) | A(dst)); - return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24)); - } - else if ((flags & REG_DEST) && op == SLJIT_MOV_SB) - return push_inst(compiler, EXTSB | S(src2) | A(dst)); - else if (dst != src2) - SLJIT_ASSERT_STOP(); - return SLJIT_SUCCESS; - - case SLJIT_MOV_UH: - case SLJIT_MOV_SH: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_SH) - return push_inst(compiler, EXTSH | S(src2) | A(dst)); - return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16)); - } - else if (dst != src2) - SLJIT_ASSERT_STOP(); - return SLJIT_SUCCESS; - - case SLJIT_NOT: - SLJIT_ASSERT(src1 == TMP_REG1); - return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2)); - - case SLJIT_NEG: - SLJIT_ASSERT(src1 == TMP_REG1); - return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2)); - - case SLJIT_CLZ: - SLJIT_ASSERT(src1 == TMP_REG1); - return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst)); + else + FAIL_IF(push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2))); + return (flags & ALT_FORM3) ? push_inst(compiler, MTXER | S(0)) : SLJIT_SUCCESS; } SLJIT_ASSERT_STOP(); return SLJIT_SUCCESS; } -static SLJIT_INLINE int emit_const(struct sljit_compiler *compiler, int reg, sljit_w init_value) +static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si reg, sljit_sw init_value) { FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16))); return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value)); @@ -252,7 +259,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad SLJIT_CACHE_FLUSH(inst, inst + 2); } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant) { sljit_ins *inst = (sljit_ins*)addr; diff --git a/src/3rd/pcre/sjppc64.c b/src/3rd/pcre/sjppc64.c index cc2ae37eb9..8eaeb41f4e 100644 --- a/src/3rd/pcre/sjppc64.c +++ b/src/3rd/pcre/sjppc64.c @@ -26,9 +26,11 @@ /* ppc 64-bit arch dependent functions. */ -#ifdef __GNUC__ +#if defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM) #define ASM_SLJIT_CLZ(src, dst) \ - asm volatile ( "cntlzd %0, %1" : "=r"(dst) : "r"(src) ) + __asm__ volatile ( "cntlzd %0, %1" : "=r"(dst) : "r"(src) ) +#elif defined(__xlc__) +#error "Please enable GCC syntax for inline assembly statements" #else #error "Must implement count leading zeroes" #endif @@ -39,7 +41,7 @@ #define PUSH_RLDICR(reg, shift) \ push_inst(compiler, RLDI(reg, reg, 63 - shift, shift, 1)) -static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w imm) +static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm) { sljit_uw tmp; sljit_uw shift; @@ -143,10 +145,74 @@ static int load_immediate(struct sljit_compiler *compiler, int reg, sljit_w imm) src1 = TMP_REG1; \ } -static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, int flags, - int dst, int src1, int src2) +static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags, + sljit_si dst, sljit_si src1, sljit_si src2) { switch (op) { + case SLJIT_MOV: + case SLJIT_MOV_P: + SLJIT_ASSERT(src1 == TMP_REG1); + if (dst != src2) + return push_inst(compiler, OR | S(src2) | A(dst) | B(src2)); + return SLJIT_SUCCESS; + + case SLJIT_MOV_UI: + case SLJIT_MOV_SI: + SLJIT_ASSERT(src1 == TMP_REG1); + if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { + if (op == SLJIT_MOV_SI) + return push_inst(compiler, EXTSW | S(src2) | A(dst)); + return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 0)); + } + else { + SLJIT_ASSERT(dst == src2); + } + return SLJIT_SUCCESS; + + case SLJIT_MOV_UB: + case SLJIT_MOV_SB: + SLJIT_ASSERT(src1 == TMP_REG1); + if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { + if (op == SLJIT_MOV_SB) + return push_inst(compiler, EXTSB | S(src2) | A(dst)); + return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24)); + } + else if ((flags & REG_DEST) && op == SLJIT_MOV_SB) + return push_inst(compiler, EXTSB | S(src2) | A(dst)); + else { + SLJIT_ASSERT(dst == src2); + } + return SLJIT_SUCCESS; + + case SLJIT_MOV_UH: + case SLJIT_MOV_SH: + SLJIT_ASSERT(src1 == TMP_REG1); + if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { + if (op == SLJIT_MOV_SH) + return push_inst(compiler, EXTSH | S(src2) | A(dst)); + return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16)); + } + else { + SLJIT_ASSERT(dst == src2); + } + return SLJIT_SUCCESS; + + case SLJIT_NOT: + SLJIT_ASSERT(src1 == TMP_REG1); + UN_EXTS(); + return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2)); + + case SLJIT_NEG: + SLJIT_ASSERT(src1 == TMP_REG1); + UN_EXTS(); + return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2)); + + case SLJIT_CLZ: + SLJIT_ASSERT(src1 == TMP_REG1); + if (flags & ALT_FORM1) + return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst)); + return push_inst(compiler, CNTLZD | RC(flags) | S(src2) | A(dst)); + case SLJIT_ADD: if (flags & ALT_FORM1) { /* Flags does not set: BIN_IMM_EXTS unnecessary. */ @@ -175,7 +241,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, case SLJIT_ADDC: if (flags & ALT_FORM1) { - FAIL_IF(push_inst(compiler, MFXER | S(0))); + FAIL_IF(push_inst(compiler, MFXER | D(0))); FAIL_IF(push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2))); return push_inst(compiler, MTXER | S(0)); } @@ -212,7 +278,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, case SLJIT_SUBC: if (flags & ALT_FORM1) { - FAIL_IF(push_inst(compiler, MFXER | S(0))); + FAIL_IF(push_inst(compiler, MFXER | D(0))); FAIL_IF(push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1))); return push_inst(compiler, MTXER | S(0)); } @@ -284,9 +350,7 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, return push_inst(compiler, RLDI(dst, src1, compiler->imm, 63 - compiler->imm, 1) | RC(flags)); } } - if (flags & ALT_FORM2) - return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2)); - return push_inst(compiler, SLD | RC(flags) | S(src1) | A(dst) | B(src2)); + return push_inst(compiler, ((flags & ALT_FORM2) ? SLW : SLD) | RC(flags) | S(src1) | A(dst) | B(src2)); case SLJIT_LSHR: if (flags & ALT_FORM1) { @@ -300,92 +364,32 @@ static SLJIT_INLINE int emit_single_op(struct sljit_compiler *compiler, int op, return push_inst(compiler, RLDI(dst, src1, 64 - compiler->imm, compiler->imm, 0) | RC(flags)); } } - if (flags & ALT_FORM2) - return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2)); - return push_inst(compiler, SRD | RC(flags) | S(src1) | A(dst) | B(src2)); + return push_inst(compiler, ((flags & ALT_FORM2) ? SRW : SRD) | RC(flags) | S(src1) | A(dst) | B(src2)); case SLJIT_ASHR: + if (flags & ALT_FORM3) + FAIL_IF(push_inst(compiler, MFXER | D(0))); if (flags & ALT_FORM1) { SLJIT_ASSERT(src2 == TMP_REG2); if (flags & ALT_FORM2) { compiler->imm &= 0x1f; - return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11)); + FAIL_IF(push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11))); } else { compiler->imm &= 0x3f; - return push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4)); + FAIL_IF(push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4))); } } - if (flags & ALT_FORM2) - return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2)); - return push_inst(compiler, SRAD | RC(flags) | S(src1) | A(dst) | B(src2)); - - case SLJIT_MOV: - SLJIT_ASSERT(src1 == TMP_REG1); - if (dst != src2) - return push_inst(compiler, OR | S(src2) | A(dst) | B(src2)); - return SLJIT_SUCCESS; - - case SLJIT_MOV_UI: - case SLJIT_MOV_SI: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_SI) - return push_inst(compiler, EXTSW | S(src2) | A(dst)); - return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 0)); - } - else if (dst != src2) - SLJIT_ASSERT_STOP(); - return SLJIT_SUCCESS; - - case SLJIT_MOV_UB: - case SLJIT_MOV_SB: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_SB) - return push_inst(compiler, EXTSB | S(src2) | A(dst)); - return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24)); - } - else if ((flags & REG_DEST) && op == SLJIT_MOV_SB) - return push_inst(compiler, EXTSB | S(src2) | A(dst)); - else if (dst != src2) - SLJIT_ASSERT_STOP(); - return SLJIT_SUCCESS; - - case SLJIT_MOV_UH: - case SLJIT_MOV_SH: - SLJIT_ASSERT(src1 == TMP_REG1); - if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) { - if (op == SLJIT_MOV_SH) - return push_inst(compiler, EXTSH | S(src2) | A(dst)); - return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16)); - } - else if (dst != src2) - SLJIT_ASSERT_STOP(); - return SLJIT_SUCCESS; - - case SLJIT_NOT: - SLJIT_ASSERT(src1 == TMP_REG1); - UN_EXTS(); - return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2)); - - case SLJIT_NEG: - SLJIT_ASSERT(src1 == TMP_REG1); - UN_EXTS(); - return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2)); - - case SLJIT_CLZ: - SLJIT_ASSERT(src1 == TMP_REG1); - if (flags & ALT_FORM1) - return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst)); - return push_inst(compiler, CNTLZD | RC(flags) | S(src2) | A(dst)); + else + FAIL_IF(push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2))); + return (flags & ALT_FORM3) ? push_inst(compiler, MTXER | S(0)) : SLJIT_SUCCESS; } SLJIT_ASSERT_STOP(); return SLJIT_SUCCESS; } -static SLJIT_INLINE int emit_const(struct sljit_compiler *compiler, int reg, sljit_w init_value) +static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si reg, sljit_sw init_value) { FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 48))); FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value >> 32))); @@ -405,7 +409,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_ad SLJIT_CACHE_FLUSH(inst, inst + 5); } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant) { sljit_ins *inst = (sljit_ins*)addr; @@ -415,14 +419,3 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constan inst[4] = (inst[4] & 0xffff0000) | (new_constant & 0xffff); SLJIT_CACHE_FLUSH(inst, inst + 5); } - -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_w addr, void* func) -{ - sljit_w* ptrs; - if (func_ptr) - *func_ptr = (void*)context; - ptrs = (sljit_w*)func; - context->addr = addr ? addr : ptrs[0]; - context->r2 = ptrs[1]; - context->r11 = ptrs[2]; -} diff --git a/src/3rd/pcre/sjppcc.c b/src/3rd/pcre/sjppcc.c index 8abcb9b4f2..6c8e5810e3 100644 --- a/src/3rd/pcre/sjppcc.c +++ b/src/3rd/pcre/sjppcc.c @@ -24,7 +24,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() +SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void) { return "PowerPC" SLJIT_CPUINFO; } @@ -33,16 +33,49 @@ SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() Both for ppc-32 and ppc-64. */ typedef sljit_ui sljit_ins; +#ifdef _AIX +#include +#endif + static void ppc_cache_flush(sljit_ins *from, sljit_ins *to) { +#ifdef _AIX + _sync_cache_range((caddr_t)from, (int)((size_t)to - (size_t)from)); +#elif defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM) +# if defined(_ARCH_PWR) || defined(_ARCH_PWR2) + /* Cache flush for POWER architecture. */ while (from < to) { -#ifdef __GNUC__ - asm volatile ( "icbi 0, %0" : : "r"(from) ); -#else -#error "Must implement icbi" -#endif + __asm__ volatile ( + "clf 0, %0\n" + "dcs\n" + : : "r"(from) + ); from++; } + __asm__ volatile ( "ics" ); +# elif defined(_ARCH_COM) && !defined(_ARCH_PPC) +# error "Cache flush is not implemented for PowerPC/POWER common mode." +# else + /* Cache flush for PowerPC architecture. */ + while (from < to) { + __asm__ volatile ( + "dcbf 0, %0\n" + "sync\n" + "icbi 0, %0\n" + : : "r"(from) + ); + from++; + } + __asm__ volatile ( "isync" ); +# endif +# ifdef __xlc__ +# warning "This file may fail to compile if -qfuncsect is used" +# endif +#elif defined(__xlc__) +#error "Please enable GCC syntax for inline assembly statements with -qasm=gcc" +#else +#error "This platform requires a cache flush implementation." +#endif /* _AIX */ } #define TMP_REG1 (SLJIT_NO_REGISTERS + 1) @@ -50,8 +83,12 @@ static void ppc_cache_flush(sljit_ins *from, sljit_ins *to) #define TMP_REG3 (SLJIT_NO_REGISTERS + 3) #define ZERO_REG (SLJIT_NO_REGISTERS + 4) -#define TMP_FREG1 (SLJIT_FLOAT_REG4 + 1) -#define TMP_FREG2 (SLJIT_FLOAT_REG4 + 2) +#define TMP_FREG1 (0) +#define TMP_FREG2 (SLJIT_FLOAT_REG6 + 1) + +static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { + 0, 3, 4, 5, 6, 7, 30, 29, 28, 27, 26, 1, 8, 9, 10, 31 +}; /* --------------------------------------------------------------------- */ /* Instrucion forms */ @@ -106,16 +143,17 @@ static void ppc_cache_flush(sljit_ins *from, sljit_ins *to) #define EXTSW (HI(31) | LO(986)) #define FABS (HI(63) | LO(264)) #define FADD (HI(63) | LO(21)) +#define FADDS (HI(59) | LO(21)) #define FCMPU (HI(63) | LO(0)) #define FDIV (HI(63) | LO(18)) +#define FDIVS (HI(59) | LO(18)) #define FMR (HI(63) | LO(72)) #define FMUL (HI(63) | LO(25)) +#define FMULS (HI(59) | LO(25)) #define FNEG (HI(63) | LO(40)) #define FSUB (HI(63) | LO(20)) +#define FSUBS (HI(59) | LO(20)) #define LD (HI(58) | 0) -#define LFD (HI(50)) -#define LFDUX (HI(31) | LO(631)) -#define LFDX (HI(31) | LO(599)) #define LWZ (HI(32)) #define MFCR (HI(31) | LO(19)) #define MFLR (HI(31) | LO(339) | 0x80000) @@ -149,9 +187,6 @@ static void ppc_cache_flush(sljit_ins *from, sljit_ins *to) #define STD (HI(62) | 0) #define STDU (HI(62) | 1) #define STDUX (HI(31) | LO(181)) -#define STFD (HI(54)) -#define STFDUX (HI(31) | LO(759)) -#define STFDX (HI(31) | LO(727)) #define STW (HI(36)) #define STWU (HI(37)) #define STWUX (HI(31) | LO(183)) @@ -167,11 +202,20 @@ static void ppc_cache_flush(sljit_ins *from, sljit_ins *to) #define SIMM_MIN (-0x8000) #define UIMM_MAX (0xffff) -static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 6] = { - 0, 3, 4, 5, 6, 7, 30, 29, 28, 27, 26, 1, 8, 9, 10, 31 -}; +#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_sw addr, void* func) +{ + sljit_sw* ptrs; + if (func_ptr) + *func_ptr = (void*)context; + ptrs = (sljit_sw*)func; + context->addr = addr ? addr : ptrs[0]; + context->r2 = ptrs[1]; + context->r11 = ptrs[2]; +} +#endif -static int push_inst(struct sljit_compiler *compiler, sljit_ins ins) +static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins) { sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins)); FAIL_IF(!ptr); @@ -180,9 +224,9 @@ static int push_inst(struct sljit_compiler *compiler, sljit_ins ins) return SLJIT_SUCCESS; } -static SLJIT_INLINE int optimize_jump(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code) +static SLJIT_INLINE sljit_si optimize_jump(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code) { - sljit_w diff; + sljit_sw diff; sljit_uw target_addr; if (jump->flags & SLJIT_REWRITABLE_JUMP) @@ -194,7 +238,7 @@ static SLJIT_INLINE int optimize_jump(struct sljit_jump *jump, sljit_ins *code_p SLJIT_ASSERT(jump->flags & JUMP_LABEL); target_addr = (sljit_uw)(code + jump->u.label->size); } - diff = ((sljit_w)target_addr - (sljit_w)(code_ptr)) & ~0x3l; + diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr)) & ~0x3l; if (jump->flags & UNCOND_B) { if (diff <= 0x01ffffff && diff >= -0x02000000) { @@ -237,8 +281,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil check_sljit_generate_code(compiler); reverse_buf(compiler); +#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) compiler->size += (compiler->size & 0x1) + (sizeof(struct sljit_function_context) / sizeof(sljit_ins)); +#else + compiler->size += (sizeof(struct sljit_function_context) / sizeof(sljit_ins)); +#endif #endif code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins)); PTR_FAIL_WITH_EXEC_IF(code); @@ -302,10 +350,10 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil SLJIT_ASSERT(!label); SLJIT_ASSERT(!jump); SLJIT_ASSERT(!const_); -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - SLJIT_ASSERT(code_ptr - code <= (int)compiler->size - ((compiler->size & 0x1) ? 3 : 2)); +#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) + SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size - (sizeof(struct sljit_function_context) / sizeof(sljit_ins))); #else - SLJIT_ASSERT(code_ptr - code <= (int)compiler->size); + SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size); #endif jump = compiler->jumps; @@ -317,7 +365,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil if (jump->flags & UNCOND_B) { if (!(jump->flags & ABSOLUTE_B)) { addr = addr - jump->addr; - SLJIT_ASSERT((sljit_w)addr <= 0x01ffffff && (sljit_w)addr >= -0x02000000); + SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000); *buf_ptr = Bx | (addr & 0x03fffffc) | ((*buf_ptr) & 0x1); } else { @@ -328,7 +376,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil else { if (!(jump->flags & ABSOLUTE_B)) { addr = addr - jump->addr; - SLJIT_ASSERT((sljit_w)addr <= 0x7fff && (sljit_w)addr >= -0x8000); + SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000); *buf_ptr = BCx | (addr & 0xfffc) | ((*buf_ptr) & 0x03ff0001); } else { @@ -354,33 +402,45 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil jump = jump->next; } - SLJIT_CACHE_FLUSH(code, code_ptr); compiler->error = SLJIT_ERR_COMPILED; - compiler->executable_size = compiler->size * sizeof(sljit_ins); + compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins); + SLJIT_CACHE_FLUSH(code, code_ptr); +#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (((sljit_w)code_ptr) & 0x4) + if (((sljit_sw)code_ptr) & 0x4) code_ptr++; - sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_w)code, sljit_generate_code); + sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_sw)code, (void*)sljit_generate_code); return code_ptr; +#else + sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_sw)code, (void*)sljit_generate_code); + return code_ptr; +#endif #else return code; #endif } +/* --------------------------------------------------------------------- */ +/* Entry, exit */ +/* --------------------------------------------------------------------- */ + /* inp_flags: */ /* Creates an index in data_transfer_insts array. */ +#define LOAD_DATA 0x01 +#define INDEXED 0x02 +#define WRITE_BACK 0x04 #define WORD_DATA 0x00 -#define BYTE_DATA 0x01 -#define HALF_DATA 0x02 -#define INT_DATA 0x03 -#define SIGNED_DATA 0x04 -#define LOAD_DATA 0x08 -#define WRITE_BACK 0x10 -#define INDEXED 0x20 +#define BYTE_DATA 0x08 +#define HALF_DATA 0x10 +#define INT_DATA 0x18 +#define SIGNED_DATA 0x20 +/* Separates integer and floating point registers */ +#define GPR_REG 0x3f +#define DOUBLE_DATA 0x40 -#define MEM_MASK 0x3f +#define MEM_MASK 0x7f /* Other inp_flags. */ @@ -389,6 +449,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil #define ALT_SIGN_EXT 0x000200 /* This flag affects the RC() and OERC() macros. */ #define ALT_SET_FLAGS 0x000400 +#define ALT_KEEP_CACHE 0x000800 #define ALT_FORM1 0x010000 #define ALT_FORM2 0x020000 #define ALT_FORM3 0x040000 @@ -425,48 +486,43 @@ ALT_FORM6 0x200000 */ #define STACK_LOAD LD #endif -static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w); - -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { CHECK_ERROR(); - check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size); + check_sljit_emit_enter(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; #endif FAIL_IF(push_inst(compiler, MFLR | D(0))); - FAIL_IF(push_inst(compiler, STACK_STORE | S(ZERO_REG) | A(SLJIT_LOCALS_REG) | IMM(-(int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_STORE | S(ZERO_REG) | A(SLJIT_LOCALS_REG) | IMM(-(sljit_si)(sizeof(sljit_sw))) )); if (saveds >= 1) - FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_REG1) | A(SLJIT_LOCALS_REG) | IMM(-2 * (int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_REG1) | A(SLJIT_LOCALS_REG) | IMM(-2 * (sljit_si)(sizeof(sljit_sw))) )); if (saveds >= 2) - FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_REG2) | A(SLJIT_LOCALS_REG) | IMM(-3 * (int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_REG2) | A(SLJIT_LOCALS_REG) | IMM(-3 * (sljit_si)(sizeof(sljit_sw))) )); if (saveds >= 3) - FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_REG3) | A(SLJIT_LOCALS_REG) | IMM(-4 * (int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_REG3) | A(SLJIT_LOCALS_REG) | IMM(-4 * (sljit_si)(sizeof(sljit_sw))) )); if (saveds >= 4) - FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_EREG1) | A(SLJIT_LOCALS_REG) | IMM(-5 * (int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_EREG1) | A(SLJIT_LOCALS_REG) | IMM(-5 * (sljit_si)(sizeof(sljit_sw))) )); if (saveds >= 5) - FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_EREG2) | A(SLJIT_LOCALS_REG) | IMM(-6 * (int)(sizeof(sljit_w))) )); - FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(SLJIT_LOCALS_REG) | IMM(sizeof(sljit_w)) )); + FAIL_IF(push_inst(compiler, STACK_STORE | S(SLJIT_SAVED_EREG2) | A(SLJIT_LOCALS_REG) | IMM(-6 * (sljit_si)(sizeof(sljit_sw))) )); + FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(SLJIT_LOCALS_REG) | IMM(sizeof(sljit_sw)) )); FAIL_IF(push_inst(compiler, ADDI | D(ZERO_REG) | A(0) | 0)); if (args >= 1) - FAIL_IF(push_inst(compiler, OR | S(SLJIT_TEMPORARY_REG1) | A(SLJIT_SAVED_REG1) | B(SLJIT_TEMPORARY_REG1))); + FAIL_IF(push_inst(compiler, OR | S(SLJIT_SCRATCH_REG1) | A(SLJIT_SAVED_REG1) | B(SLJIT_SCRATCH_REG1))); if (args >= 2) - FAIL_IF(push_inst(compiler, OR | S(SLJIT_TEMPORARY_REG2) | A(SLJIT_SAVED_REG2) | B(SLJIT_TEMPORARY_REG2))); + FAIL_IF(push_inst(compiler, OR | S(SLJIT_SCRATCH_REG2) | A(SLJIT_SAVED_REG2) | B(SLJIT_SCRATCH_REG2))); if (args >= 3) - FAIL_IF(push_inst(compiler, OR | S(SLJIT_TEMPORARY_REG3) | A(SLJIT_SAVED_REG3) | B(SLJIT_TEMPORARY_REG3))); + FAIL_IF(push_inst(compiler, OR | S(SLJIT_SCRATCH_REG3) | A(SLJIT_SAVED_REG3) | B(SLJIT_SCRATCH_REG3))); -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - compiler->local_size = (1 + saveds + 2) * sizeof(sljit_w) + local_size; +#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) + compiler->local_size = (1 + saveds + 6 + 8) * sizeof(sljit_sw) + local_size; #else - compiler->local_size = (1 + saveds + 7 + 8) * sizeof(sljit_w) + local_size; + compiler->local_size = (1 + saveds + 2) * sizeof(sljit_sw) + local_size; #endif compiler->local_size = (compiler->local_size + 15) & ~0xf; @@ -489,30 +545,29 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { CHECK_ERROR_VOID(); - check_sljit_set_context(compiler, args, temporaries, saveds, local_size); + check_sljit_set_context(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; #endif -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - compiler->local_size = (1 + saveds + 2) * sizeof(sljit_w) + local_size; +#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) + compiler->local_size = (1 + saveds + 6 + 8) * sizeof(sljit_sw) + local_size; #else - compiler->local_size = (1 + saveds + 7 + 8) * sizeof(sljit_w) + local_size; + compiler->local_size = (1 + saveds + 2) * sizeof(sljit_sw) + local_size; #endif compiler->local_size = (compiler->local_size + 15) & ~0xf; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) { CHECK_ERROR(); check_sljit_emit_return(compiler, op, src, srcw); - ADJUST_LOCAL_OFFSET(src, srcw); FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); @@ -523,18 +578,18 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, FAIL_IF(push_inst(compiler, ADD | D(SLJIT_LOCALS_REG) | A(SLJIT_LOCALS_REG) | B(0))); } - FAIL_IF(push_inst(compiler, STACK_LOAD | D(0) | A(SLJIT_LOCALS_REG) | IMM(sizeof(sljit_w)))); + FAIL_IF(push_inst(compiler, STACK_LOAD | D(0) | A(SLJIT_LOCALS_REG) | IMM(sizeof(sljit_sw)))); if (compiler->saveds >= 5) - FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_EREG2) | A(SLJIT_LOCALS_REG) | IMM(-6 * (int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_EREG2) | A(SLJIT_LOCALS_REG) | IMM(-6 * (sljit_si)(sizeof(sljit_sw))) )); if (compiler->saveds >= 4) - FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_EREG1) | A(SLJIT_LOCALS_REG) | IMM(-5 * (int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_EREG1) | A(SLJIT_LOCALS_REG) | IMM(-5 * (sljit_si)(sizeof(sljit_sw))) )); if (compiler->saveds >= 3) - FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_REG3) | A(SLJIT_LOCALS_REG) | IMM(-4 * (int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_REG3) | A(SLJIT_LOCALS_REG) | IMM(-4 * (sljit_si)(sizeof(sljit_sw))) )); if (compiler->saveds >= 2) - FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_REG2) | A(SLJIT_LOCALS_REG) | IMM(-3 * (int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_REG2) | A(SLJIT_LOCALS_REG) | IMM(-3 * (sljit_si)(sizeof(sljit_sw))) )); if (compiler->saveds >= 1) - FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_REG1) | A(SLJIT_LOCALS_REG) | IMM(-2 * (int)(sizeof(sljit_w))) )); - FAIL_IF(push_inst(compiler, STACK_LOAD | D(ZERO_REG) | A(SLJIT_LOCALS_REG) | IMM(-(int)(sizeof(sljit_w))) )); + FAIL_IF(push_inst(compiler, STACK_LOAD | D(SLJIT_SAVED_REG1) | A(SLJIT_LOCALS_REG) | IMM(-2 * (sljit_si)(sizeof(sljit_sw))) )); + FAIL_IF(push_inst(compiler, STACK_LOAD | D(ZERO_REG) | A(SLJIT_LOCALS_REG) | IMM(-(sljit_si)(sizeof(sljit_sw))) )); FAIL_IF(push_inst(compiler, MTLR | S(0))); FAIL_IF(push_inst(compiler, BLR)); @@ -562,117 +617,139 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, #define UPDATE_REQ 0x20000 #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) -#define ARCH_DEPEND(a, b) a -#define GET_INST_CODE(inst) (inst) +#define ARCH_32_64(a, b) a +#define INST_CODE_AND_DST(inst, flags, reg) \ + ((inst) | (((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg))) #else -#define ARCH_DEPEND(a, b) b -#define GET_INST_CODE(index) ((inst) & ~(ADDR_MODE2 | UPDATE_REQ)) +#define ARCH_32_64(a, b) b +#define INST_CODE_AND_DST(inst, flags, reg) \ + (((inst) & ~(ADDR_MODE2 | UPDATE_REQ)) | (((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg))) #endif -static SLJIT_CONST sljit_ins data_transfer_insts[64] = { +static SLJIT_CONST sljit_ins data_transfer_insts[64 + 8] = { -/* No write-back. */ +/* -------- Unsigned -------- */ -/* i n s u w */ ARCH_DEPEND(HI(36) /* stw */, HI(62) | ADDR_MODE2 | 0x0 /* std */), -/* i n s u b */ HI(38) /* stb */, -/* i n s u h */ HI(44) /* sth*/, -/* i n s u i */ HI(36) /* stw */, +/* Word. */ -/* i n s s w */ ARCH_DEPEND(HI(36) /* stw */, HI(62) | ADDR_MODE2 | 0x0 /* std */), -/* i n s s b */ HI(38) /* stb */, -/* i n s s h */ HI(44) /* sth*/, -/* i n s s i */ HI(36) /* stw */, +/* u w n i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | ADDR_MODE2 | 0x0 /* std */), +/* u w n i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | ADDR_MODE2 | 0x0 /* ld */), +/* u w n x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */), +/* u w n x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */), -/* i n l u w */ ARCH_DEPEND(HI(32) /* lwz */, HI(58) | ADDR_MODE2 | 0x0 /* ld */), -/* i n l u b */ HI(34) /* lbz */, -/* i n l u h */ HI(40) /* lhz */, -/* i n l u i */ HI(32) /* lwz */, +/* u w w i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | ADDR_MODE2 | 0x1 /* stdu */), +/* u w w i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | ADDR_MODE2 | 0x1 /* ldu */), +/* u w w x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */), +/* u w w x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */), -/* i n l s w */ ARCH_DEPEND(HI(32) /* lwz */, HI(58) | ADDR_MODE2 | 0x0 /* ld */), -/* i n l s b */ HI(34) /* lbz */ /* EXTS_REQ */, -/* i n l s h */ HI(42) /* lha */, -/* i n l s i */ ARCH_DEPEND(HI(32) /* lwz */, HI(58) | ADDR_MODE2 | 0x2 /* lwa */), +/* Byte. */ -/* Write-back. */ +/* u b n i s */ HI(38) /* stb */, +/* u b n i l */ HI(34) /* lbz */, +/* u b n x s */ HI(31) | LO(215) /* stbx */, +/* u b n x l */ HI(31) | LO(87) /* lbzx */, -/* i w s u w */ ARCH_DEPEND(HI(37) /* stwu */, HI(62) | ADDR_MODE2 | 0x1 /* stdu */), -/* i w s u b */ HI(39) /* stbu */, -/* i w s u h */ HI(45) /* sthu */, -/* i w s u i */ HI(37) /* stwu */, +/* u b w i s */ HI(39) /* stbu */, +/* u b w i l */ HI(35) /* lbzu */, +/* u b w x s */ HI(31) | LO(247) /* stbux */, +/* u b w x l */ HI(31) | LO(119) /* lbzux */, -/* i w s s w */ ARCH_DEPEND(HI(37) /* stwu */, HI(62) | ADDR_MODE2 | 0x1 /* stdu */), -/* i w s s b */ HI(39) /* stbu */, -/* i w s s h */ HI(45) /* sthu */, -/* i w s s i */ HI(37) /* stwu */, +/* Half. */ -/* i w l u w */ ARCH_DEPEND(HI(33) /* lwzu */, HI(58) | ADDR_MODE2 | 0x1 /* ldu */), -/* i w l u b */ HI(35) /* lbzu */, -/* i w l u h */ HI(41) /* lhzu */, -/* i w l u i */ HI(33) /* lwzu */, +/* u h n i s */ HI(44) /* sth */, +/* u h n i l */ HI(40) /* lhz */, +/* u h n x s */ HI(31) | LO(407) /* sthx */, +/* u h n x l */ HI(31) | LO(279) /* lhzx */, -/* i w l s w */ ARCH_DEPEND(HI(33) /* lwzu */, HI(58) | ADDR_MODE2 | 0x1 /* ldu */), -/* i w l s b */ HI(35) /* lbzu */ /* EXTS_REQ */, -/* i w l s h */ HI(43) /* lhau */, -/* i w l s i */ ARCH_DEPEND(HI(33) /* lwzu */, HI(58) | ADDR_MODE2 | UPDATE_REQ | 0x2 /* lwa */), +/* u h w i s */ HI(45) /* sthu */, +/* u h w i l */ HI(41) /* lhzu */, +/* u h w x s */ HI(31) | LO(439) /* sthux */, +/* u h w x l */ HI(31) | LO(311) /* lhzux */, -/* ---------- */ -/* Indexed */ -/* ---------- */ +/* Int. */ -/* No write-back. */ +/* u i n i s */ HI(36) /* stw */, +/* u i n i l */ HI(32) /* lwz */, +/* u i n x s */ HI(31) | LO(151) /* stwx */, +/* u i n x l */ HI(31) | LO(23) /* lwzx */, -/* x n s u w */ ARCH_DEPEND(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */), -/* x n s u b */ HI(31) | LO(215) /* stbx */, -/* x n s u h */ HI(31) | LO(407) /* sthx */, -/* x n s u i */ HI(31) | LO(151) /* stwx */, +/* u i w i s */ HI(37) /* stwu */, +/* u i w i l */ HI(33) /* lwzu */, +/* u i w x s */ HI(31) | LO(183) /* stwux */, +/* u i w x l */ HI(31) | LO(55) /* lwzux */, -/* x n s s w */ ARCH_DEPEND(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */), -/* x n s s b */ HI(31) | LO(215) /* stbx */, -/* x n s s h */ HI(31) | LO(407) /* sthx */, -/* x n s s i */ HI(31) | LO(151) /* stwx */, +/* -------- Signed -------- */ -/* x n l u w */ ARCH_DEPEND(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */), -/* x n l u b */ HI(31) | LO(87) /* lbzx */, -/* x n l u h */ HI(31) | LO(279) /* lhzx */, -/* x n l u i */ HI(31) | LO(23) /* lwzx */, +/* Word. */ -/* x n l s w */ ARCH_DEPEND(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */), -/* x n l s b */ HI(31) | LO(87) /* lbzx */ /* EXTS_REQ */, -/* x n l s h */ HI(31) | LO(343) /* lhax */, -/* x n l s i */ ARCH_DEPEND(HI(31) | LO(23) /* lwzx */, HI(31) | LO(341) /* lwax */), +/* s w n i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | ADDR_MODE2 | 0x0 /* std */), +/* s w n i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | ADDR_MODE2 | 0x0 /* ld */), +/* s w n x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */), +/* s w n x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */), -/* Write-back. */ +/* s w w i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | ADDR_MODE2 | 0x1 /* stdu */), +/* s w w i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | ADDR_MODE2 | 0x1 /* ldu */), +/* s w w x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */), +/* s w w x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */), -/* x w s u w */ ARCH_DEPEND(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */), -/* x w s u b */ HI(31) | LO(247) /* stbux */, -/* x w s u h */ HI(31) | LO(439) /* sthux */, -/* x w s u i */ HI(31) | LO(183) /* stwux */, +/* Byte. */ -/* x w s s w */ ARCH_DEPEND(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */), -/* x w s s b */ HI(31) | LO(247) /* stbux */, -/* x w s s h */ HI(31) | LO(439) /* sthux */, -/* x w s s i */ HI(31) | LO(183) /* stwux */, +/* s b n i s */ HI(38) /* stb */, +/* s b n i l */ HI(34) /* lbz */ /* EXTS_REQ */, +/* s b n x s */ HI(31) | LO(215) /* stbx */, +/* s b n x l */ HI(31) | LO(87) /* lbzx */ /* EXTS_REQ */, -/* x w l u w */ ARCH_DEPEND(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */), -/* x w l u b */ HI(31) | LO(119) /* lbzux */, -/* x w l u h */ HI(31) | LO(311) /* lhzux */, -/* x w l u i */ HI(31) | LO(55) /* lwzux */, +/* s b w i s */ HI(39) /* stbu */, +/* s b w i l */ HI(35) /* lbzu */ /* EXTS_REQ */, +/* s b w x s */ HI(31) | LO(247) /* stbux */, +/* s b w x l */ HI(31) | LO(119) /* lbzux */ /* EXTS_REQ */, -/* x w l s w */ ARCH_DEPEND(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */), -/* x w l s b */ HI(31) | LO(119) /* lbzux */ /* EXTS_REQ */, -/* x w l s h */ HI(31) | LO(375) /* lhaux */, -/* x w l s i */ ARCH_DEPEND(HI(31) | LO(55) /* lwzux */, HI(31) | LO(373) /* lwaux */) +/* Half. */ + +/* s h n i s */ HI(44) /* sth */, +/* s h n i l */ HI(42) /* lha */, +/* s h n x s */ HI(31) | LO(407) /* sthx */, +/* s h n x l */ HI(31) | LO(343) /* lhax */, + +/* s h w i s */ HI(45) /* sthu */, +/* s h w i l */ HI(43) /* lhau */, +/* s h w x s */ HI(31) | LO(439) /* sthux */, +/* s h w x l */ HI(31) | LO(375) /* lhaux */, + +/* Int. */ + +/* s i n i s */ HI(36) /* stw */, +/* s i n i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | ADDR_MODE2 | 0x2 /* lwa */), +/* s i n x s */ HI(31) | LO(151) /* stwx */, +/* s i n x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(341) /* lwax */), + +/* s i w i s */ HI(37) /* stwu */, +/* s i w i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | ADDR_MODE2 | UPDATE_REQ | 0x2 /* lwa */), +/* s i w x s */ HI(31) | LO(183) /* stwux */, +/* s i w x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(373) /* lwaux */), + +/* -------- Double -------- */ + +/* d n i s */ HI(54) /* stfd */, +/* d n i l */ HI(50) /* lfd */, +/* d n x s */ HI(31) | LO(727) /* stfdx */, +/* d n x l */ HI(31) | LO(599) /* lfdx */, + +/* s n i s */ HI(52) /* stfs */, +/* s n i l */ HI(48) /* lfs */, +/* s n x s */ HI(31) | LO(663) /* stfsx */, +/* s n x l */ HI(31) | LO(535) /* lfsx */, }; -#undef ARCH_DEPEND +#undef ARCH_32_64 /* Simple cases, (no caching is required). */ -static int getput_arg_fast(struct sljit_compiler *compiler, int inp_flags, int reg, int arg, sljit_w argw) +static sljit_si getput_arg_fast(struct sljit_compiler *compiler, sljit_si inp_flags, sljit_si reg, sljit_si arg, sljit_sw argw) { sljit_ins inst; #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - int tmp_reg; + sljit_si tmp_reg; #endif SLJIT_ASSERT(arg & SLJIT_MEM); @@ -684,7 +761,7 @@ static int getput_arg_fast(struct sljit_compiler *compiler, int inp_flags, int r inst = data_transfer_insts[(inp_flags & ~WRITE_BACK) & MEM_MASK]; SLJIT_ASSERT(!(inst & (ADDR_MODE2 | UPDATE_REQ))); - push_inst(compiler, GET_INST_CODE(inst) | D(reg) | IMM(argw)); + push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | IMM(argw)); return -1; } #else @@ -694,11 +771,11 @@ static int getput_arg_fast(struct sljit_compiler *compiler, int inp_flags, int r if (inp_flags & ARG_TEST) return 1; - push_inst(compiler, GET_INST_CODE(inst) | D(reg) | IMM(argw)); + push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | IMM(argw)); return -1; } #endif - return (inp_flags & ARG_TEST) ? SLJIT_SUCCESS : 0; + return 0; } if (!(arg & 0xf0)) { @@ -709,7 +786,7 @@ static int getput_arg_fast(struct sljit_compiler *compiler, int inp_flags, int r inst = data_transfer_insts[inp_flags & MEM_MASK]; SLJIT_ASSERT(!(inst & (ADDR_MODE2 | UPDATE_REQ))); - push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(arg & 0xf) | IMM(argw)); + push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & 0xf) | IMM(argw)); return -1; } #else @@ -725,7 +802,7 @@ static int getput_arg_fast(struct sljit_compiler *compiler, int inp_flags, int r arg = tmp_reg | SLJIT_MEM; argw = 0; } - push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(arg & 0xf) | IMM(argw)); + push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & 0xf) | IMM(argw)); return -1; } #endif @@ -735,28 +812,24 @@ static int getput_arg_fast(struct sljit_compiler *compiler, int inp_flags, int r return 1; inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK]; SLJIT_ASSERT(!(inst & (ADDR_MODE2 | UPDATE_REQ))); - push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(arg & 0xf) | B((arg >> 4) & 0xf)); + push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & 0xf) | B((arg >> 4) & 0xf)); return -1; } - return (inp_flags & ARG_TEST) ? SLJIT_SUCCESS : 0; + return 0; } /* See getput_arg below. Note: can_cache is called only for binary operators. Those operator always uses word arguments without write back. */ -static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw) +static sljit_si can_cache(sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw) { - SLJIT_ASSERT(arg & SLJIT_MEM); - SLJIT_ASSERT(next_arg & SLJIT_MEM); + SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM)); - if (!(arg & 0xf)) { - if ((next_arg & SLJIT_MEM) && ((sljit_uw)argw - (sljit_uw)next_argw <= SIMM_MAX || (sljit_uw)next_argw - (sljit_uw)argw <= SIMM_MAX)) - return 1; - return 0; - } + if (!(arg & 0xf)) + return (next_arg & SLJIT_MEM) && ((sljit_uw)argw - (sljit_uw)next_argw <= SIMM_MAX || (sljit_uw)next_argw - (sljit_uw)argw <= SIMM_MAX); if (arg & 0xf0) - return 0; + return ((arg & 0xf0) == (next_arg & 0xf0) && (argw & 0x3) == (next_argw & 0x3)); if (argw <= SIMM_MAX && argw >= SIMM_MIN) { if (arg == next_arg && (next_argw >= SIMM_MAX && next_argw <= SIMM_MIN)) @@ -782,21 +855,17 @@ static int can_cache(int arg, sljit_w argw, int next_arg, sljit_w next_argw) #endif /* Emit the necessary instructions. See can_cache above. */ -static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, int arg, sljit_w argw, int next_arg, sljit_w next_argw) +static sljit_si getput_arg(struct sljit_compiler *compiler, sljit_si inp_flags, sljit_si reg, sljit_si arg, sljit_sw argw, sljit_si next_arg, sljit_sw next_argw) { - int tmp_r; + sljit_si tmp_r; sljit_ins inst; SLJIT_ASSERT(arg & SLJIT_MEM); - tmp_r = (inp_flags & LOAD_DATA) ? reg : TMP_REG3; - if ((arg & 0xf) == tmp_r) { - /* Special case for "mov reg, [reg, ... ]". - Caching would not happen anyway. */ - tmp_r = TMP_REG3; - compiler->cache_arg = 0; - compiler->cache_argw = 0; - } + tmp_r = ((inp_flags & LOAD_DATA) && ((inp_flags) & MEM_MASK) <= GPR_REG) ? reg : TMP_REG1; + /* Special case for "mov reg, [reg, ... ]". */ + if ((arg & 0xf) == tmp_r) + tmp_r = TMP_REG1; if (!(arg & 0xf)) { inst = data_transfer_insts[(inp_flags & ~WRITE_BACK) & MEM_MASK]; @@ -804,7 +873,7 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i argw = argw - compiler->cache_argw; ADJUST_CACHED_IMM(argw); SLJIT_ASSERT(!(inst & UPDATE_REQ)); - return push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(TMP_REG3) | IMM(argw)); + return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(TMP_REG3) | IMM(argw)); } if ((next_arg & SLJIT_MEM) && (argw - next_argw <= SIMM_MAX || next_argw - argw <= SIMM_MAX)) { @@ -816,21 +885,31 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i } FAIL_IF(load_immediate(compiler, tmp_r, argw)); - return push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(tmp_r)); + return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(tmp_r)); } if (SLJIT_UNLIKELY(arg & 0xf0)) { argw &= 0x3; /* Otherwise getput_arg_fast would capture it. */ SLJIT_ASSERT(argw); + + if ((SLJIT_MEM | (arg & 0xf0)) == compiler->cache_arg && argw == compiler->cache_argw) + tmp_r = TMP_REG3; + else { + if ((arg & 0xf0) == (next_arg & 0xf0) && argw == (next_argw & 0x3)) { + compiler->cache_arg = SLJIT_MEM | (arg & 0xf0); + compiler->cache_argw = argw; + tmp_r = TMP_REG3; + } #if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - FAIL_IF(push_inst(compiler, RLWINM | S((arg >> 4) & 0xf) | A(tmp_r) | (argw << 11) | ((31 - argw) << 1))); + FAIL_IF(push_inst(compiler, RLWINM | S((arg >> 4) & 0xf) | A(tmp_r) | (argw << 11) | ((31 - argw) << 1))); #else - FAIL_IF(push_inst(compiler, RLDI(tmp_r, (arg >> 4) & 0xf, argw, 63 - argw, 1))); + FAIL_IF(push_inst(compiler, RLDI(tmp_r, (arg >> 4) & 0xf, argw, 63 - argw, 1))); #endif + } inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK]; SLJIT_ASSERT(!(inst & (ADDR_MODE2 | UPDATE_REQ))); - return push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(arg & 0xf) | B(tmp_r)); + return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & 0xf) | B(tmp_r)); } inst = data_transfer_insts[inp_flags & MEM_MASK]; @@ -839,13 +918,13 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i SLJIT_ASSERT(!(inp_flags & WRITE_BACK)); argw = argw - compiler->cache_argw; ADJUST_CACHED_IMM(argw); - return push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(TMP_REG3) | IMM(argw)); + return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(TMP_REG3) | IMM(argw)); } if ((compiler->cache_arg & SLJIT_IMM) && compiler->cache_argw == argw) { inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK]; SLJIT_ASSERT(!(inst & (ADDR_MODE2 | UPDATE_REQ))); - return push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(arg & 0xf) | B(TMP_REG3)); + return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & 0xf) | B(TMP_REG3)); } if (argw == next_argw && (next_arg & SLJIT_MEM)) { @@ -857,7 +936,7 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK]; SLJIT_ASSERT(!(inst & (ADDR_MODE2 | UPDATE_REQ))); - return push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(arg & 0xf) | B(TMP_REG3)); + return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & 0xf) | B(TMP_REG3)); } if (arg == next_arg && !(inp_flags & WRITE_BACK) && ((sljit_uw)argw - (sljit_uw)next_argw <= SIMM_MAX || (sljit_uw)next_argw - (sljit_uw)argw <= SIMM_MAX)) { @@ -868,49 +947,58 @@ static int getput_arg(struct sljit_compiler *compiler, int inp_flags, int reg, i compiler->cache_arg = arg; compiler->cache_argw = argw; - return push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(TMP_REG3)); + return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(TMP_REG3)); } /* Get the indexed version instead of the normal one. */ inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK]; SLJIT_ASSERT(!(inst & (ADDR_MODE2 | UPDATE_REQ))); FAIL_IF(load_immediate(compiler, tmp_r, argw)); - return push_inst(compiler, GET_INST_CODE(inst) | D(reg) | A(arg & 0xf) | B(tmp_r)); + return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & 0xf) | B(tmp_r)); } -static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit_si flags, sljit_si reg, sljit_si arg1, sljit_sw arg1w, sljit_si arg2, sljit_sw arg2w) +{ + if (getput_arg_fast(compiler, flags, reg, arg1, arg1w)) + return compiler->error; + return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w); +} + +static sljit_si emit_op(struct sljit_compiler *compiler, sljit_si op, sljit_si input_flags, + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { /* arg1 goes to TMP_REG1 or src reg arg2 goes to TMP_REG2, imm or src reg TMP_REG3 can be used for caching result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */ - int dst_r; - int src1_r; - int src2_r; - int sugg_src2_r = TMP_REG2; - int flags = inp_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_FORM6 | ALT_SIGN_EXT | ALT_SET_FLAGS); + sljit_si dst_r; + sljit_si src1_r; + sljit_si src2_r; + sljit_si sugg_src2_r = TMP_REG2; + sljit_si flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_FORM6 | ALT_SIGN_EXT | ALT_SET_FLAGS); - compiler->cache_arg = 0; - compiler->cache_argw = 0; + if (!(input_flags & ALT_KEEP_CACHE)) { + compiler->cache_arg = 0; + compiler->cache_argw = 0; + } /* Destination check. */ - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= ZERO_REG) { + if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) { + if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM)) + return SLJIT_SUCCESS; + dst_r = TMP_REG2; + } + else if (dst <= ZERO_REG) { dst_r = dst; flags |= REG_DEST; if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) sugg_src2_r = dst_r; } - else if (dst == SLJIT_UNUSED) { - if (op >= SLJIT_MOV && op <= SLJIT_MOVU_SI && !(src2 & SLJIT_MEM)) - return SLJIT_SUCCESS; - dst_r = TMP_REG2; - } else { SLJIT_ASSERT(dst & SLJIT_MEM); - if (getput_arg_fast(compiler, inp_flags | ARG_TEST, TMP_REG2, dst, dstw)) { + if (getput_arg_fast(compiler, input_flags | ARG_TEST, TMP_REG2, dst, dstw)) { flags |= FAST_DEST; dst_r = TMP_REG2; } @@ -921,23 +1009,15 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, } /* Source 1. */ - if (src1 >= SLJIT_TEMPORARY_REG1 && src1 <= ZERO_REG) { + if (src1 <= ZERO_REG) { src1_r = src1; flags |= REG1_SOURCE; } else if (src1 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if ((inp_flags & 0x3) == INT_DATA) { - if (inp_flags & SIGNED_DATA) - src1w = (signed int)src1w; - else - src1w = (unsigned int)src1w; - } -#endif FAIL_IF(load_immediate(compiler, TMP_REG1, src1w)); src1_r = TMP_REG1; } - else if (getput_arg_fast(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w)) { + else if (getput_arg_fast(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w)) { FAIL_IF(compiler->error); src1_r = TMP_REG1; } @@ -945,25 +1025,17 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, src1_r = 0; /* Source 2. */ - if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= ZERO_REG) { + if (src2 <= ZERO_REG) { src2_r = src2; flags |= REG2_SOURCE; if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_SI) dst_r = src2_r; } else if (src2 & SLJIT_IMM) { -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if ((inp_flags & 0x3) == INT_DATA) { - if (inp_flags & SIGNED_DATA) - src2w = (signed int)src2w; - else - src2w = (unsigned int)src2w; - } -#endif FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w)); src2_r = sugg_src2_r; } - else if (getput_arg_fast(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w)) { + else if (getput_arg_fast(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w)) { FAIL_IF(compiler->error); src2_r = sugg_src2_r; } @@ -974,26 +1046,26 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, All arguments are complex addressing modes, and it is a binary operator. */ if (src1_r == 0 && src2_r == 0 && dst_r == 0) { if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { - FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG2, src2, src2w, src1, src1w)); - FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw)); + FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG2, src2, src2w, src1, src1w)); + FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw)); } else { - FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w)); - FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw)); + FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w)); + FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw)); } src1_r = TMP_REG1; src2_r = TMP_REG2; } else if (src1_r == 0 && src2_r == 0) { - FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w)); + FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w)); src1_r = TMP_REG1; } else if (src1_r == 0 && dst_r == 0) { - FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw)); + FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw)); src1_r = TMP_REG1; } else if (src2_r == 0 && dst_r == 0) { - FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw)); + FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw)); src2_r = sugg_src2_r; } @@ -1001,12 +1073,12 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, dst_r = TMP_REG2; if (src1_r == 0) { - FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, 0, 0)); + FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, 0, 0)); src1_r = TMP_REG1; } if (src2_r == 0) { - FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w, 0, 0)); + FAIL_IF(getput_arg(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w, 0, 0)); src2_r = sugg_src2_r; } @@ -1014,14 +1086,14 @@ static int emit_op(struct sljit_compiler *compiler, int op, int inp_flags, if (flags & (FAST_DEST | SLOW_DEST)) { if (flags & FAST_DEST) - FAIL_IF(getput_arg_fast(compiler, inp_flags, dst_r, dst, dstw)); + FAIL_IF(getput_arg_fast(compiler, input_flags, dst_r, dst, dstw)); else - FAIL_IF(getput_arg(compiler, inp_flags, dst_r, dst, dstw, 0, 0)); + FAIL_IF(getput_arg(compiler, input_flags, dst_r, dst, dstw, 0, 0)); } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) { CHECK_ERROR(); check_sljit_emit_op0(compiler, op); @@ -1033,120 +1105,161 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int break; case SLJIT_UMUL: case SLJIT_SMUL: - FAIL_IF(push_inst(compiler, OR | S(SLJIT_TEMPORARY_REG1) | A(TMP_REG1) | B(SLJIT_TEMPORARY_REG1))); + FAIL_IF(push_inst(compiler, OR | S(SLJIT_SCRATCH_REG1) | A(TMP_REG1) | B(SLJIT_SCRATCH_REG1))); #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_TEMPORARY_REG1) | A(TMP_REG1) | B(SLJIT_TEMPORARY_REG2))); - return push_inst(compiler, (GET_OPCODE(op) == SLJIT_UMUL ? MULHDU : MULHD) | D(SLJIT_TEMPORARY_REG2) | A(TMP_REG1) | B(SLJIT_TEMPORARY_REG2)); + FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_SCRATCH_REG1) | A(TMP_REG1) | B(SLJIT_SCRATCH_REG2))); + return push_inst(compiler, (GET_OPCODE(op) == SLJIT_UMUL ? MULHDU : MULHD) | D(SLJIT_SCRATCH_REG2) | A(TMP_REG1) | B(SLJIT_SCRATCH_REG2)); #else - FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_TEMPORARY_REG1) | A(TMP_REG1) | B(SLJIT_TEMPORARY_REG2))); - return push_inst(compiler, (GET_OPCODE(op) == SLJIT_UMUL ? MULHWU : MULHW) | D(SLJIT_TEMPORARY_REG2) | A(TMP_REG1) | B(SLJIT_TEMPORARY_REG2)); + FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_SCRATCH_REG1) | A(TMP_REG1) | B(SLJIT_SCRATCH_REG2))); + return push_inst(compiler, (GET_OPCODE(op) == SLJIT_UMUL ? MULHWU : MULHW) | D(SLJIT_SCRATCH_REG2) | A(TMP_REG1) | B(SLJIT_SCRATCH_REG2)); #endif case SLJIT_UDIV: case SLJIT_SDIV: - FAIL_IF(push_inst(compiler, OR | S(SLJIT_TEMPORARY_REG1) | A(TMP_REG1) | B(SLJIT_TEMPORARY_REG1))); + FAIL_IF(push_inst(compiler, OR | S(SLJIT_SCRATCH_REG1) | A(TMP_REG1) | B(SLJIT_SCRATCH_REG1))); #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) if (op & SLJIT_INT_OP) { - FAIL_IF(push_inst(compiler, (GET_OPCODE(op) == SLJIT_UDIV ? DIVWU : DIVW) | D(SLJIT_TEMPORARY_REG1) | A(TMP_REG1) | B(SLJIT_TEMPORARY_REG2))); - FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_TEMPORARY_REG2) | A(SLJIT_TEMPORARY_REG1) | B(SLJIT_TEMPORARY_REG2))); - return push_inst(compiler, SUBF | D(SLJIT_TEMPORARY_REG2) | A(SLJIT_TEMPORARY_REG2) | B(TMP_REG1)); + FAIL_IF(push_inst(compiler, (GET_OPCODE(op) == SLJIT_UDIV ? DIVWU : DIVW) | D(SLJIT_SCRATCH_REG1) | A(TMP_REG1) | B(SLJIT_SCRATCH_REG2))); + FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_SCRATCH_REG2) | A(SLJIT_SCRATCH_REG1) | B(SLJIT_SCRATCH_REG2))); + return push_inst(compiler, SUBF | D(SLJIT_SCRATCH_REG2) | A(SLJIT_SCRATCH_REG2) | B(TMP_REG1)); } - FAIL_IF(push_inst(compiler, (GET_OPCODE(op) == SLJIT_UDIV ? DIVDU : DIVD) | D(SLJIT_TEMPORARY_REG1) | A(TMP_REG1) | B(SLJIT_TEMPORARY_REG2))); - FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_TEMPORARY_REG2) | A(SLJIT_TEMPORARY_REG1) | B(SLJIT_TEMPORARY_REG2))); - return push_inst(compiler, SUBF | D(SLJIT_TEMPORARY_REG2) | A(SLJIT_TEMPORARY_REG2) | B(TMP_REG1)); + FAIL_IF(push_inst(compiler, (GET_OPCODE(op) == SLJIT_UDIV ? DIVDU : DIVD) | D(SLJIT_SCRATCH_REG1) | A(TMP_REG1) | B(SLJIT_SCRATCH_REG2))); + FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_SCRATCH_REG2) | A(SLJIT_SCRATCH_REG1) | B(SLJIT_SCRATCH_REG2))); + return push_inst(compiler, SUBF | D(SLJIT_SCRATCH_REG2) | A(SLJIT_SCRATCH_REG2) | B(TMP_REG1)); #else - FAIL_IF(push_inst(compiler, (GET_OPCODE(op) == SLJIT_UDIV ? DIVWU : DIVW) | D(SLJIT_TEMPORARY_REG1) | A(TMP_REG1) | B(SLJIT_TEMPORARY_REG2))); - FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_TEMPORARY_REG2) | A(SLJIT_TEMPORARY_REG1) | B(SLJIT_TEMPORARY_REG2))); - return push_inst(compiler, SUBF | D(SLJIT_TEMPORARY_REG2) | A(SLJIT_TEMPORARY_REG2) | B(TMP_REG1)); + FAIL_IF(push_inst(compiler, (GET_OPCODE(op) == SLJIT_UDIV ? DIVWU : DIVW) | D(SLJIT_SCRATCH_REG1) | A(TMP_REG1) | B(SLJIT_SCRATCH_REG2))); + FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_SCRATCH_REG2) | A(SLJIT_SCRATCH_REG1) | B(SLJIT_SCRATCH_REG2))); + return push_inst(compiler, SUBF | D(SLJIT_SCRATCH_REG2) | A(SLJIT_SCRATCH_REG2) | B(TMP_REG1)); #endif } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +#define EMIT_MOV(type, type_flags, type_cast) \ + emit_op(compiler, (src & SLJIT_IMM) ? SLJIT_MOV : type, flags | (type_flags), dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? type_cast srcw : srcw) + +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) { - int inp_flags = GET_FLAGS(op) ? ALT_SET_FLAGS : 0; + sljit_si flags = GET_FLAGS(op) ? ALT_SET_FLAGS : 0; + sljit_si op_flags = GET_ALL_FLAGS(op); CHECK_ERROR(); check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw); ADJUST_LOCAL_OFFSET(dst, dstw); ADJUST_LOCAL_OFFSET(src, srcw); + op = GET_OPCODE(op); if ((src & SLJIT_IMM) && srcw == 0) src = ZERO_REG; -#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - if (op & SLJIT_INT_OP) { - inp_flags |= INT_DATA | SIGNED_DATA; - if (src & SLJIT_IMM) - srcw = (int)srcw; - } -#endif - if (op & SLJIT_SET_O) + if (op_flags & SLJIT_SET_O) FAIL_IF(push_inst(compiler, MTXER | S(ZERO_REG))); - switch (GET_OPCODE(op)) { - case SLJIT_MOV: - return emit_op(compiler, SLJIT_MOV, inp_flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + if (op_flags & SLJIT_INT_OP) { + if (op >= SLJIT_MOV && op <= SLJIT_MOVU_P) { + if (src <= ZERO_REG && src == dst) { + if (!TYPE_CAST_NEEDED(op)) + return SLJIT_SUCCESS; + } +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) + if (op == SLJIT_MOV_SI && (src & SLJIT_MEM)) + op = SLJIT_MOV_UI; + if (op == SLJIT_MOVU_SI && (src & SLJIT_MEM)) + op = SLJIT_MOVU_UI; + if (op == SLJIT_MOV_UI && (src & SLJIT_IMM)) + op = SLJIT_MOV_SI; + if (op == SLJIT_MOVU_UI && (src & SLJIT_IMM)) + op = SLJIT_MOVU_SI; +#endif + } +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) + else { + /* Most operations expect sign extended arguments. */ + flags |= INT_DATA | SIGNED_DATA; + if (src & SLJIT_IMM) + srcw = (sljit_si)srcw; + } +#endif + } + switch (op) { + case SLJIT_MOV: + case SLJIT_MOV_P: +#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) case SLJIT_MOV_UI: - return emit_op(compiler, SLJIT_MOV_UI, inp_flags | INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + case SLJIT_MOV_SI: +#endif + return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) + case SLJIT_MOV_UI: + return EMIT_MOV(SLJIT_MOV_UI, INT_DATA, (sljit_ui)); case SLJIT_MOV_SI: - return emit_op(compiler, SLJIT_MOV_SI, inp_flags | INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + return EMIT_MOV(SLJIT_MOV_SI, INT_DATA | SIGNED_DATA, (sljit_si)); +#endif case SLJIT_MOV_UB: - return emit_op(compiler, SLJIT_MOV_UB, inp_flags | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw); + return EMIT_MOV(SLJIT_MOV_UB, BYTE_DATA, (sljit_ub)); case SLJIT_MOV_SB: - return emit_op(compiler, SLJIT_MOV_SB, inp_flags | BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw); + return EMIT_MOV(SLJIT_MOV_SB, BYTE_DATA | SIGNED_DATA, (sljit_sb)); case SLJIT_MOV_UH: - return emit_op(compiler, SLJIT_MOV_UH, inp_flags | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw); + return EMIT_MOV(SLJIT_MOV_UH, HALF_DATA, (sljit_uh)); case SLJIT_MOV_SH: - return emit_op(compiler, SLJIT_MOV_SH, inp_flags | HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw); + return EMIT_MOV(SLJIT_MOV_SH, HALF_DATA | SIGNED_DATA, (sljit_sh)); case SLJIT_MOVU: - return emit_op(compiler, SLJIT_MOV, inp_flags | WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); - + case SLJIT_MOVU_P: +#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) case SLJIT_MOVU_UI: - return emit_op(compiler, SLJIT_MOV_UI, inp_flags | INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); + case SLJIT_MOVU_SI: +#endif + return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); + +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) + case SLJIT_MOVU_UI: + return EMIT_MOV(SLJIT_MOV_UI, INT_DATA | WRITE_BACK, (sljit_ui)); case SLJIT_MOVU_SI: - return emit_op(compiler, SLJIT_MOV_SI, inp_flags | INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw); + return EMIT_MOV(SLJIT_MOV_SI, INT_DATA | SIGNED_DATA | WRITE_BACK, (sljit_si)); +#endif case SLJIT_MOVU_UB: - return emit_op(compiler, SLJIT_MOV_UB, inp_flags | BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw); + return EMIT_MOV(SLJIT_MOV_UB, BYTE_DATA | WRITE_BACK, (sljit_ub)); case SLJIT_MOVU_SB: - return emit_op(compiler, SLJIT_MOV_SB, inp_flags | BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw); + return EMIT_MOV(SLJIT_MOV_SB, BYTE_DATA | SIGNED_DATA | WRITE_BACK, (sljit_sb)); case SLJIT_MOVU_UH: - return emit_op(compiler, SLJIT_MOV_UH, inp_flags | HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw); + return EMIT_MOV(SLJIT_MOV_UH, HALF_DATA | WRITE_BACK, (sljit_uh)); case SLJIT_MOVU_SH: - return emit_op(compiler, SLJIT_MOV_SH, inp_flags | HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw); + return EMIT_MOV(SLJIT_MOV_SH, HALF_DATA | SIGNED_DATA | WRITE_BACK, (sljit_sh)); case SLJIT_NOT: - return emit_op(compiler, SLJIT_NOT, inp_flags, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_NOT, flags, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_NEG: - return emit_op(compiler, SLJIT_NEG, inp_flags, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_NEG, flags, dst, dstw, TMP_REG1, 0, src, srcw); case SLJIT_CLZ: #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) - return emit_op(compiler, SLJIT_CLZ, inp_flags | (!(op & SLJIT_INT_OP) ? 0 : ALT_FORM1), dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_CLZ, flags | (!(op_flags & SLJIT_INT_OP) ? 0 : ALT_FORM1), dst, dstw, TMP_REG1, 0, src, srcw); #else - return emit_op(compiler, SLJIT_CLZ, inp_flags, dst, dstw, TMP_REG1, 0, src, srcw); + return emit_op(compiler, SLJIT_CLZ, flags, dst, dstw, TMP_REG1, 0, src, srcw); #endif } return SLJIT_SUCCESS; } +#undef EMIT_MOV + #define TEST_SL_IMM(src, srcw) \ (((src) & SLJIT_IMM) && (srcw) <= SIMM_MAX && (srcw) >= SIMM_MIN) @@ -1180,12 +1293,12 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int ((src) & SLJIT_IMM) #endif -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +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) { - int inp_flags = GET_FLAGS(op) ? ALT_SET_FLAGS : 0; + sljit_si flags = GET_FLAGS(op) ? ALT_SET_FLAGS : 0; CHECK_ERROR(); check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w); @@ -1200,80 +1313,83 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) if (op & SLJIT_INT_OP) { - inp_flags |= INT_DATA | SIGNED_DATA; + /* Most operations expect sign extended arguments. */ + flags |= INT_DATA | SIGNED_DATA; if (src1 & SLJIT_IMM) - src1w = (src1w << 32) >> 32; + src1w = (sljit_si)(src1w); if (src2 & SLJIT_IMM) - src2w = (src2w << 32) >> 32; + src2w = (sljit_si)(src2w); if (GET_FLAGS(op)) - inp_flags |= ALT_SIGN_EXT; + flags |= ALT_SIGN_EXT; } #endif if (op & SLJIT_SET_O) FAIL_IF(push_inst(compiler, MTXER | S(ZERO_REG))); + if (src2 == TMP_REG2) + flags |= ALT_KEEP_CACHE; switch (GET_OPCODE(op)) { case SLJIT_ADD: if (!GET_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) { if (TEST_SL_IMM(src2, src2w)) { compiler->imm = src2w & 0xffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); } if (TEST_SL_IMM(src1, src1w)) { compiler->imm = src1w & 0xffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); } if (TEST_SH_IMM(src2, src2w)) { compiler->imm = (src2w >> 16) & 0xffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); } if (TEST_SH_IMM(src1, src1w)) { compiler->imm = (src1w >> 16) & 0xffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0); } /* Range between -1 and -32768 is covered above. */ if (TEST_ADD_IMM(src2, src2w)) { compiler->imm = src2w & 0xffffffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0); } if (TEST_ADD_IMM(src1, src1w)) { compiler->imm = src1w & 0xffffffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0); } } if (!(GET_FLAGS(op) & (SLJIT_SET_E | SLJIT_SET_O))) { if (TEST_SL_IMM(src2, src2w)) { compiler->imm = src2w & 0xffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); } if (TEST_SL_IMM(src1, src1w)) { compiler->imm = src1w & 0xffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0); } } - return emit_op(compiler, SLJIT_ADD, inp_flags, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, SLJIT_ADD, flags, dst, dstw, src1, src1w, src2, src2w); case SLJIT_ADDC: - return emit_op(compiler, SLJIT_ADDC, inp_flags | (!(op & SLJIT_KEEP_FLAGS) ? 0 : ALT_FORM1), dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, SLJIT_ADDC, flags | (!(op & SLJIT_KEEP_FLAGS) ? 0 : ALT_FORM1), dst, dstw, src1, src1w, src2, src2w); case SLJIT_SUB: if (!GET_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) { if (TEST_SL_IMM(src2, -src2w)) { compiler->imm = (-src2w) & 0xffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); } if (TEST_SL_IMM(src1, src1w)) { compiler->imm = src1w & 0xffff; - return emit_op(compiler, SLJIT_SUB, inp_flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); } if (TEST_SH_IMM(src2, -src2w)) { compiler->imm = ((-src2w) >> 16) & 0xffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); } /* Range between -1 and -32768 is covered above. */ if (TEST_ADD_IMM(src2, -src2w)) { compiler->imm = -src2w & 0xffffffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0); } } if (dst == SLJIT_UNUSED && (op & (SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U)) && !(op & (SLJIT_SET_O | SLJIT_SET_C))) { @@ -1281,55 +1397,55 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int /* We know ALT_SIGN_EXT is set if it is an SLJIT_INT_OP on 64 bit systems. */ if (TEST_SL_IMM(src2, src2w)) { compiler->imm = src2w & 0xffff; - return emit_op(compiler, SLJIT_SUB, inp_flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); } if (GET_FLAGS(op) == SLJIT_SET_E && TEST_SL_IMM(src1, src1w)) { compiler->imm = src1w & 0xffff; - return emit_op(compiler, SLJIT_SUB, inp_flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0); } } if (!(op & (SLJIT_SET_E | SLJIT_SET_S))) { /* We know ALT_SIGN_EXT is set if it is an SLJIT_INT_OP on 64 bit systems. */ if (TEST_UL_IMM(src2, src2w)) { compiler->imm = src2w & 0xffff; - return emit_op(compiler, SLJIT_SUB, inp_flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); } - return emit_op(compiler, SLJIT_SUB, inp_flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w); } if ((src2 & SLJIT_IMM) && src2w >= 0 && src2w <= 0x7fff) { compiler->imm = src2w; - return emit_op(compiler, SLJIT_SUB, inp_flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); } - return emit_op(compiler, SLJIT_SUB, inp_flags | ((op & SLJIT_SET_U) ? ALT_FORM4 : 0) | ((op & (SLJIT_SET_E | SLJIT_SET_S)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, SLJIT_SUB, flags | ((op & SLJIT_SET_U) ? ALT_FORM4 : 0) | ((op & (SLJIT_SET_E | SLJIT_SET_S)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w); } if (!(op & (SLJIT_SET_E | SLJIT_SET_S | SLJIT_SET_U | SLJIT_SET_O))) { if (TEST_SL_IMM(src2, -src2w)) { compiler->imm = (-src2w) & 0xffff; - return emit_op(compiler, SLJIT_ADD, inp_flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); } } /* We know ALT_SIGN_EXT is set if it is an SLJIT_INT_OP on 64 bit systems. */ - return emit_op(compiler, SLJIT_SUB, inp_flags | (!(op & SLJIT_SET_U) ? 0 : ALT_FORM6), dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, SLJIT_SUB, flags | (!(op & SLJIT_SET_U) ? 0 : ALT_FORM6), dst, dstw, src1, src1w, src2, src2w); case SLJIT_SUBC: - return emit_op(compiler, SLJIT_SUBC, inp_flags | (!(op & SLJIT_KEEP_FLAGS) ? 0 : ALT_FORM1), dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, SLJIT_SUBC, flags | (!(op & SLJIT_KEEP_FLAGS) ? 0 : ALT_FORM1), dst, dstw, src1, src1w, src2, src2w); case SLJIT_MUL: #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) if (op & SLJIT_INT_OP) - inp_flags |= ALT_FORM2; + flags |= ALT_FORM2; #endif if (!GET_FLAGS(op)) { if (TEST_SL_IMM(src2, src2w)) { compiler->imm = src2w & 0xffff; - return emit_op(compiler, SLJIT_MUL, inp_flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); } if (TEST_SL_IMM(src1, src1w)) { compiler->imm = src1w & 0xffff; - return emit_op(compiler, SLJIT_MUL, inp_flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); } } - return emit_op(compiler, SLJIT_MUL, inp_flags, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, SLJIT_MUL, flags, dst, dstw, src1, src1w, src2, src2w); case SLJIT_AND: case SLJIT_OR: @@ -1338,58 +1454,67 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int if (!GET_FLAGS(op) || GET_OPCODE(op) == SLJIT_AND) { if (TEST_UL_IMM(src2, src2w)) { compiler->imm = src2w; - return emit_op(compiler, GET_OPCODE(op), inp_flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); } if (TEST_UL_IMM(src1, src1w)) { compiler->imm = src1w; - return emit_op(compiler, GET_OPCODE(op), inp_flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0); } if (TEST_UH_IMM(src2, src2w)) { compiler->imm = (src2w >> 16) & 0xffff; - return emit_op(compiler, GET_OPCODE(op), inp_flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0); } if (TEST_UH_IMM(src1, src1w)) { compiler->imm = (src1w >> 16) & 0xffff; - return emit_op(compiler, GET_OPCODE(op), inp_flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0); } } if (!GET_FLAGS(op) && GET_OPCODE(op) != SLJIT_AND) { if (TEST_UI_IMM(src2, src2w)) { compiler->imm = src2w; - return emit_op(compiler, GET_OPCODE(op), inp_flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0); } if (TEST_UI_IMM(src1, src1w)) { compiler->imm = src1w; - return emit_op(compiler, GET_OPCODE(op), inp_flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0); + return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0); } } - return emit_op(compiler, GET_OPCODE(op), inp_flags, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w); + case SLJIT_ASHR: + if (op & SLJIT_KEEP_FLAGS) + flags |= ALT_FORM3; + /* Fall through. */ case SLJIT_SHL: case SLJIT_LSHR: - case SLJIT_ASHR: #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) if (op & SLJIT_INT_OP) - inp_flags |= ALT_FORM2; + flags |= ALT_FORM2; #endif if (src2 & SLJIT_IMM) { compiler->imm = src2w; - return emit_op(compiler, GET_OPCODE(op), inp_flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); + return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0); } - return emit_op(compiler, GET_OPCODE(op), inp_flags, dst, dstw, src1, src1w, src2, src2w); + return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w); } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg) { check_sljit_get_register_index(reg); return reg_map[reg]; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, int size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg) +{ + check_sljit_get_float_register_index(reg); + return reg; +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, + void *instruction, sljit_si size) { CHECK_ERROR(); check_sljit_emit_op_custom(compiler, instruction, size); @@ -1402,106 +1527,77 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compile /* Floating point operators */ /* --------------------------------------------------------------------- */ -SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void) { /* Always available. */ return 1; } -static int emit_fpu_data_transfer(struct sljit_compiler *compiler, int fpu_reg, int load, int arg, sljit_w argw) +#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_SINGLE_OP) >> 6)) +#define SELECT_FOP(op, single, double) ((op & SLJIT_SINGLE_OP) ? single : double) + +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - SLJIT_ASSERT(arg & SLJIT_MEM); - - /* Fast loads and stores. */ - if (!(arg & 0xf0)) { - /* Both for (arg & 0xf) == SLJIT_UNUSED and (arg & 0xf) != SLJIT_UNUSED. */ - if (argw <= SIMM_MAX && argw >= SIMM_MIN) - return push_inst(compiler, (load ? LFD : STFD) | FD(fpu_reg) | A(arg & 0xf) | IMM(argw)); - } - - if (arg & 0xf0) { - argw &= 0x3; - if (argw) { -#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) - FAIL_IF(push_inst(compiler, RLWINM | S((arg >> 4) & 0xf) | A(TMP_REG2) | (argw << 11) | ((31 - argw) << 1))); -#else - FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, (arg >> 4) & 0xf, argw, 63 - argw, 1))); -#endif - return push_inst(compiler, (load ? LFDX : STFDX) | FD(fpu_reg) | A(arg & 0xf) | B(TMP_REG2)); - } - return push_inst(compiler, (load ? LFDX : STFDX) | FD(fpu_reg) | A(arg & 0xf) | B((arg >> 4) & 0xf)); - } - - /* Use cache. */ - if (compiler->cache_arg == arg && argw - compiler->cache_argw <= SIMM_MAX && argw - compiler->cache_argw >= SIMM_MIN) - return push_inst(compiler, (load ? LFD : STFD) | FD(fpu_reg) | A(TMP_REG3) | IMM(argw - compiler->cache_argw)); - - /* Put value to cache. */ - compiler->cache_arg = arg; - compiler->cache_argw = argw; - - FAIL_IF(load_immediate(compiler, TMP_REG3, argw)); - if (!(arg & 0xf)) - return push_inst(compiler, (load ? LFDX : STFDX) | FD(fpu_reg) | A(0) | B(TMP_REG3)); - return push_inst(compiler, (load ? LFDUX : STFDUX) | FD(fpu_reg) | A(TMP_REG3) | B(arg & 0xf)); -} - -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) -{ - int dst_fr; + sljit_si dst_fr; CHECK_ERROR(); check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw); + SLJIT_COMPILE_ASSERT((SLJIT_SINGLE_OP == 0x100) && !(DOUBLE_DATA & 0x4), float_transfer_bit_error); compiler->cache_arg = 0; compiler->cache_argw = 0; - if (GET_OPCODE(op) == SLJIT_FCMP) { - if (dst > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 1, dst, dstw)); + if (GET_OPCODE(op) == SLJIT_CMPD) { + if (dst > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, dst, dstw, src, srcw)); dst = TMP_FREG1; } - if (src > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG2, 1, src, srcw)); + + if (src > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src, srcw, 0, 0)); src = TMP_FREG2; } + return push_inst(compiler, FCMPU | CRD(4) | FA(dst) | FB(src)); } - dst_fr = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG1 : dst; + dst_fr = (dst > SLJIT_FLOAT_REG6) ? TMP_FREG1 : dst; - if (src > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, dst_fr, 1, src, srcw)); + if (src > SLJIT_FLOAT_REG6) { + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_fr, src, srcw, dst, dstw)); src = dst_fr; } - switch (op) { - case SLJIT_FMOV: + switch (GET_OPCODE(op)) { + case SLJIT_MOVD: if (src != dst_fr && dst_fr != TMP_FREG1) FAIL_IF(push_inst(compiler, FMR | FD(dst_fr) | FB(src))); break; - case SLJIT_FNEG: + case SLJIT_NEGD: FAIL_IF(push_inst(compiler, FNEG | FD(dst_fr) | FB(src))); break; - case SLJIT_FABS: + case SLJIT_ABSD: FAIL_IF(push_inst(compiler, FABS | FD(dst_fr) | FB(src))); break; } - if (dst_fr == TMP_FREG1) - FAIL_IF(emit_fpu_data_transfer(compiler, src, 0, dst, dstw)); + if (dst_fr == TMP_FREG1) { + if (GET_OPCODE(op) == SLJIT_MOVD) + dst_fr = src; + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), dst_fr, dst, dstw, 0, 0)); + } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(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) { - int dst_fr; + sljit_si dst_fr, flags = 0; CHECK_ERROR(); check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w); @@ -1509,69 +1605,100 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, in compiler->cache_arg = 0; compiler->cache_argw = 0; - dst_fr = (dst > SLJIT_FLOAT_REG4) ? TMP_FREG1 : dst; + dst_fr = (dst > SLJIT_FLOAT_REG6) ? TMP_FREG2 : dst; - if (src2 > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG2, 1, src2, src2w)); - src2 = TMP_FREG2; + if (src1 > SLJIT_FLOAT_REG6) { + if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w)) { + FAIL_IF(compiler->error); + src1 = TMP_FREG1; + } else + flags |= ALT_FORM1; } - if (src1 > SLJIT_FLOAT_REG4) { - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 1, src1, src1w)); + if (src2 > SLJIT_FLOAT_REG6) { + if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w)) { + FAIL_IF(compiler->error); + src2 = TMP_FREG2; + } else + flags |= ALT_FORM2; + } + + if ((flags & (ALT_FORM1 | ALT_FORM2)) == (ALT_FORM1 | ALT_FORM2)) { + if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) { + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, src1, src1w)); + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw)); + } + else { + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w)); + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw)); + } + } + else if (flags & ALT_FORM1) + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw)); + else if (flags & ALT_FORM2) + FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw)); + + if (flags & ALT_FORM1) src1 = TMP_FREG1; - } + if (flags & ALT_FORM2) + src2 = TMP_FREG2; - switch (op) { - case SLJIT_FADD: - FAIL_IF(push_inst(compiler, FADD | FD(dst_fr) | FA(src1) | FB(src2))); + switch (GET_OPCODE(op)) { + case SLJIT_ADDD: + FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADD) | FD(dst_fr) | FA(src1) | FB(src2))); break; - case SLJIT_FSUB: - FAIL_IF(push_inst(compiler, FSUB | FD(dst_fr) | FA(src1) | FB(src2))); + case SLJIT_SUBD: + FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUB) | FD(dst_fr) | FA(src1) | FB(src2))); break; - case SLJIT_FMUL: - FAIL_IF(push_inst(compiler, FMUL | FD(dst_fr) | FA(src1) | FC(src2) /* FMUL use FC as src2 */)); + case SLJIT_MULD: + FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMUL) | FD(dst_fr) | FA(src1) | FC(src2) /* FMUL use FC as src2 */)); break; - case SLJIT_FDIV: - FAIL_IF(push_inst(compiler, FDIV | FD(dst_fr) | FA(src1) | FB(src2))); + case SLJIT_DIVD: + FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIV) | FD(dst_fr) | FA(src1) | FB(src2))); break; } - if (dst_fr == TMP_FREG1) - FAIL_IF(emit_fpu_data_transfer(compiler, TMP_FREG1, 0, dst, dstw)); + if (dst_fr == TMP_FREG2) + FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0)); return SLJIT_SUCCESS; } +#undef FLOAT_DATA +#undef SELECT_FOP + /* --------------------------------------------------------------------- */ /* Other instructions */ /* --------------------------------------------------------------------- */ -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw) +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); ADJUST_LOCAL_OFFSET(dst, dstw); - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) - return push_inst(compiler, MFLR | D(dst)); - else if (dst & SLJIT_MEM) { - FAIL_IF(push_inst(compiler, MFLR | D(TMP_REG2))); - return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0); - } + /* For UNUSED dst. Uncommon, but possible. */ + if (dst == SLJIT_UNUSED) + return SLJIT_SUCCESS; - return SLJIT_SUCCESS; + if (dst <= ZERO_REG) + return push_inst(compiler, MFLR | D(dst)); + + /* Memory. */ + FAIL_IF(push_inst(compiler, MFLR | D(TMP_REG2))); + return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw) +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); ADJUST_LOCAL_OFFSET(src, srcw); - if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) + if (src <= ZERO_REG) FAIL_IF(push_inst(compiler, MTLR | S(src))); else { if (src & SLJIT_MEM) @@ -1603,7 +1730,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi return label; } -static sljit_ins get_bo_bi_flags(struct sljit_compiler *compiler, int type) +static sljit_ins get_bo_bi_flags(sljit_si type) { switch (type) { case SLJIT_C_EQUAL: @@ -1654,10 +1781,10 @@ static sljit_ins get_bo_bi_flags(struct sljit_compiler *compiler, int type) case SLJIT_C_FLOAT_NOT_EQUAL: return (4 << 21) | ((4 + 2) << 16); - case SLJIT_C_FLOAT_NAN: + case SLJIT_C_FLOAT_UNORDERED: return (12 << 21) | ((4 + 3) << 16); - case SLJIT_C_FLOAT_NOT_NAN: + case SLJIT_C_FLOAT_ORDERED: return (4 << 21) | ((4 + 3) << 16); default: @@ -1666,7 +1793,7 @@ static sljit_ins get_bo_bi_flags(struct sljit_compiler *compiler, int type) } } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, int type) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type) { struct sljit_jump *jump; sljit_ins bo_bi_flags; @@ -1674,7 +1801,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile CHECK_ERROR_PTR(); check_sljit_emit_jump(compiler, type); - bo_bi_flags = get_bo_bi_flags(compiler, type & 0xff); + bo_bi_flags = get_bo_bi_flags(type & 0xff); if (!bo_bi_flags) return NULL; @@ -1694,20 +1821,16 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile return jump; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, int type, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw) { - sljit_ins bo_bi_flags; struct sljit_jump *jump = NULL; - int src_r; + sljit_si src_r; CHECK_ERROR(); check_sljit_emit_ijump(compiler, type, src, srcw); ADJUST_LOCAL_OFFSET(src, srcw); - bo_bi_flags = get_bo_bi_flags(compiler, type); - FAIL_IF(!bo_bi_flags); - - if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) + if (src <= ZERO_REG) src_r = src; else if (src & SLJIT_IMM) { jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump)); @@ -1726,7 +1849,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i FAIL_IF(push_inst(compiler, MTCTR | S(src_r))); if (jump) jump->addr = compiler->size; - return push_inst(compiler, BCCTR | bo_bi_flags | (type >= SLJIT_FAST_CALL ? 1 : 0)); + return push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0)); } /* Get a bit from CR, all other bits are zeroed. */ @@ -1737,18 +1860,37 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i #define INVERT_BIT(dst) \ FAIL_IF(push_inst(compiler, XORI | S(dst) | A(dst) | 0x1)); -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compiler, int op, int dst, sljit_w dstw, int type) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw, + sljit_si type) { - int reg; + sljit_si reg, input_flags; + sljit_si flags = GET_ALL_FLAGS(op); CHECK_ERROR(); - check_sljit_emit_cond_value(compiler, op, dst, dstw, type); + check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type); ADJUST_LOCAL_OFFSET(dst, dstw); if (dst == SLJIT_UNUSED) return SLJIT_SUCCESS; - reg = (op == SLJIT_MOV && dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2; + op = GET_OPCODE(op); + reg = (op < SLJIT_ADD && dst <= ZERO_REG) ? dst : TMP_REG2; + + compiler->cache_arg = 0; + compiler->cache_argw = 0; + if (op >= SLJIT_ADD && (src & SLJIT_MEM)) { + ADJUST_LOCAL_OFFSET(src, srcw); +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) + input_flags = (flags & SLJIT_INT_OP) ? INT_DATA : WORD_DATA; +#else + input_flags = WORD_DATA; +#endif + FAIL_IF(emit_op_mem2(compiler, input_flags | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw)); + src = TMP_REG1; + srcw = 0; + } switch (type) { case SLJIT_C_EQUAL: @@ -1820,11 +1962,11 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compil INVERT_BIT(reg); break; - case SLJIT_C_FLOAT_NAN: + case SLJIT_C_FLOAT_UNORDERED: GET_CR_BIT(4 + 3, reg); break; - case SLJIT_C_FLOAT_NOT_NAN: + case SLJIT_C_FLOAT_ORDERED: GET_CR_BIT(4 + 3, reg); INVERT_BIT(reg); break; @@ -1834,18 +1976,31 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compil break; } - if (GET_OPCODE(op) == SLJIT_OR) - return emit_op(compiler, GET_OPCODE(op), GET_FLAGS(op) ? ALT_SET_FLAGS : 0, dst, dstw, dst, dstw, TMP_REG2, 0); + if (op < SLJIT_ADD) { +#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) + if (op == SLJIT_MOV) + input_flags = WORD_DATA; + else { + op = SLJIT_MOV_UI; + input_flags = INT_DATA; + } +#else + op = SLJIT_MOV; + input_flags = WORD_DATA; +#endif + return (reg == TMP_REG2) ? emit_op(compiler, op, input_flags, dst, dstw, TMP_REG1, 0, TMP_REG2, 0) : SLJIT_SUCCESS; + } - if (reg == TMP_REG2) - return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0); - return SLJIT_SUCCESS; +#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) + compiler->skip_checks = 1; +#endif + return sljit_emit_op2(compiler, op | flags, dst, dstw, src, srcw, TMP_REG2, 0); } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w init_value) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value) { struct sljit_const *const_; - int reg; + sljit_si reg; CHECK_ERROR_PTR(); check_sljit_emit_const(compiler, dst, dstw, init_value); @@ -1855,7 +2010,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi PTR_FAIL_IF(!const_); set_const(const_, compiler); - reg = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REG2; + reg = (dst <= ZERO_REG) ? dst : TMP_REG2; PTR_FAIL_IF(emit_const(compiler, reg, init_value)); diff --git a/src/3rd/pcre/sjutils.c b/src/3rd/pcre/sjutils.c index 21f5e94485..b29b4036b3 100644 --- a/src/3rd/pcre/sjutils.c +++ b/src/3rd/pcre/sjutils.c @@ -106,10 +106,10 @@ SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) #else /* _WIN32 */ -#include "pthread.h" - #if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) +#include + static pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER; static SLJIT_INLINE void allocator_grab_lock(void) @@ -126,6 +126,8 @@ static SLJIT_INLINE void allocator_release_lock(void) #if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK) +#include + static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER; SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void) @@ -146,17 +148,57 @@ SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void) /* Stack */ /* ------------------------------------------------------------------------ */ -#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) +#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) || (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) #ifdef _WIN32 #include "windows.h" #else +/* Provides mmap function. */ #include +/* For detecting the page size. */ #include + +#ifndef MAP_ANON + +#include + +/* Some old systems does not have MAP_ANON. */ +static sljit_si dev_zero = -1; + +#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED) + +static SLJIT_INLINE sljit_si open_dev_zero(void) +{ + dev_zero = open("/dev/zero", O_RDWR); + return dev_zero < 0; +} + +#else /* SLJIT_SINGLE_THREADED */ + +#include + +static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER; + +static SLJIT_INLINE sljit_si open_dev_zero(void) +{ + pthread_mutex_lock(&dev_zero_mutex); + dev_zero = open("/dev/zero", O_RDWR); + pthread_mutex_unlock(&dev_zero_mutex); + return dev_zero < 0; +} + +#endif /* SLJIT_SINGLE_THREADED */ + #endif +#endif + +#endif /* SLJIT_UTIL_STACK || SLJIT_EXECUTABLE_ALLOCATOR */ + +#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) + /* Planning to make it even more clever in the future. */ -static sljit_w sljit_page_align = 0; +static sljit_sw sljit_page_align = 0; SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit) { @@ -195,7 +237,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(slj return NULL; #ifdef _WIN32 - base.ptr = VirtualAlloc(0, max_limit, MEM_RESERVE, PAGE_READWRITE); + base.ptr = VirtualAlloc(NULL, max_limit, MEM_RESERVE, PAGE_READWRITE); if (!base.ptr) { SLJIT_FREE(stack); return NULL; @@ -208,7 +250,17 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(slj return NULL; } #else - base.ptr = mmap(0, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +#ifdef MAP_ANON + base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +#else + if (dev_zero < 0) { + if (open_dev_zero()) { + SLJIT_FREE(stack); + return NULL; + } + } + base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0); +#endif if (base.ptr == MAP_FAILED) { SLJIT_FREE(stack); return NULL; @@ -233,7 +285,7 @@ SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack* st SLJIT_FREE(stack); } -SLJIT_API_FUNC_ATTRIBUTE sljit_w SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit) +SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit) { sljit_uw aligned_old_limit; sljit_uw aligned_new_limit; @@ -262,8 +314,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_w SLJIT_CALL sljit_stack_resize(struct sljit_stac } aligned_new_limit = (new_limit + sljit_page_align) & ~sljit_page_align; aligned_old_limit = (stack->limit + sljit_page_align) & ~sljit_page_align; + /* If madvise is available, we release the unnecessary space. */ +#if defined(MADV_DONTNEED) + if (aligned_new_limit < aligned_old_limit) + madvise((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MADV_DONTNEED); +#elif defined(POSIX_MADV_DONTNEED) if (aligned_new_limit < aligned_old_limit) posix_madvise((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, POSIX_MADV_DONTNEED); +#endif stack->limit = new_limit; return 0; #endif diff --git a/src/3rd/pcre/sjx8632.c b/src/3rd/pcre/sjx8632.c index e9558250fc..2866e8f2a1 100644 --- a/src/3rd/pcre/sjx8632.c +++ b/src/3rd/pcre/sjx8632.c @@ -26,30 +26,30 @@ /* x86 32-bit arch dependent functions. */ -static int emit_do_imm(struct sljit_compiler *compiler, sljit_ub opcode, sljit_w imm) +static sljit_si emit_do_imm(struct sljit_compiler *compiler, sljit_ub opcode, sljit_sw imm) { - sljit_ub *buf; + sljit_ub *inst; - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_w)); - FAIL_IF(!buf); - INC_SIZE(1 + sizeof(sljit_w)); - *buf++ = opcode; - *(sljit_w*)buf = imm; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_sw)); + FAIL_IF(!inst); + INC_SIZE(1 + sizeof(sljit_sw)); + *inst++ = opcode; + *(sljit_sw*)inst = imm; return SLJIT_SUCCESS; } -static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, int type) +static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_si type) { if (type == SLJIT_JUMP) { - *code_ptr++ = 0xe9; + *code_ptr++ = JMP_i32; jump->addr++; } else if (type >= SLJIT_FAST_CALL) { - *code_ptr++ = 0xe8; + *code_ptr++ = CALL_i32; jump->addr++; } else { - *code_ptr++ = 0x0f; + *code_ptr++ = GROUP_0F; *code_ptr++ = get_jump_code(type); jump->addr += 2; } @@ -57,22 +57,22 @@ static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ if (jump->flags & JUMP_LABEL) jump->flags |= PATCH_MW; else - *(sljit_w*)code_ptr = jump->u.target - (jump->addr + 4); + *(sljit_sw*)code_ptr = jump->u.target - (jump->addr + 4); code_ptr += 4; return code_ptr; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { - int size; - int locals_offset; - sljit_ub *buf; + sljit_si size; + sljit_si locals_offset; + sljit_ub *inst; CHECK_ERROR(); - check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size); + check_sljit_emit_enter(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; compiler->args = args; compiler->flags_saved = 0; @@ -85,15 +85,15 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i #else size = 1 + (saveds <= 3 ? saveds : 3) + (args > 0 ? (2 + args * 3) : 0); #endif - buf = (sljit_ub*)ensure_buf(compiler, 1 + size); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + size); + FAIL_IF(!inst); INC_SIZE(size); PUSH_REG(reg_map[TMP_REGISTER]); #if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) if (args > 0) { - *buf++ = 0x8b; - *buf++ = 0xc4 | (reg_map[TMP_REGISTER] << 3); + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_map[TMP_REGISTER] << 3) | 0x4 /* esp */; } #endif if (saveds > 2) @@ -105,102 +105,125 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i #if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) if (args > 0) { - *buf++ = 0x8b; - *buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG1] << 3) | reg_map[SLJIT_TEMPORARY_REG3]; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG1] << 3) | reg_map[SLJIT_SCRATCH_REG3]; } if (args > 1) { - *buf++ = 0x8b; - *buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG2] << 3) | reg_map[SLJIT_TEMPORARY_REG2]; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG2] << 3) | reg_map[SLJIT_SCRATCH_REG2]; } if (args > 2) { - *buf++ = 0x8b; - *buf++ = 0x44 | (reg_map[SLJIT_SAVED_REG3] << 3); - *buf++ = 0x24; - *buf++ = sizeof(sljit_w) * (3 + 2); /* saveds >= 3 as well. */ + *inst++ = MOV_r_rm; + *inst++ = MOD_DISP8 | (reg_map[SLJIT_SAVED_REG3] << 3) | 0x4 /* esp */; + *inst++ = 0x24; + *inst++ = sizeof(sljit_sw) * (3 + 2); /* saveds >= 3 as well. */ } #else if (args > 0) { - *buf++ = 0x8b; - *buf++ = 0x40 | (reg_map[SLJIT_SAVED_REG1] << 3) | reg_map[TMP_REGISTER]; - *buf++ = sizeof(sljit_w) * 2; + *inst++ = MOV_r_rm; + *inst++ = MOD_DISP8 | (reg_map[SLJIT_SAVED_REG1] << 3) | reg_map[TMP_REGISTER]; + *inst++ = sizeof(sljit_sw) * 2; } if (args > 1) { - *buf++ = 0x8b; - *buf++ = 0x40 | (reg_map[SLJIT_SAVED_REG2] << 3) | reg_map[TMP_REGISTER]; - *buf++ = sizeof(sljit_w) * 3; + *inst++ = MOV_r_rm; + *inst++ = MOD_DISP8 | (reg_map[SLJIT_SAVED_REG2] << 3) | reg_map[TMP_REGISTER]; + *inst++ = sizeof(sljit_sw) * 3; } if (args > 2) { - *buf++ = 0x8b; - *buf++ = 0x40 | (reg_map[SLJIT_SAVED_REG3] << 3) | reg_map[TMP_REGISTER]; - *buf++ = sizeof(sljit_w) * 4; + *inst++ = MOV_r_rm; + *inst++ = MOD_DISP8 | (reg_map[SLJIT_SAVED_REG3] << 3) | reg_map[TMP_REGISTER]; + *inst++ = sizeof(sljit_sw) * 4; } #endif +#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) locals_offset = 2 * sizeof(sljit_uw); - compiler->temporaries_start = locals_offset; - if (temporaries > 3) - locals_offset += (temporaries - 3) * sizeof(sljit_uw); +#else + SLJIT_COMPILE_ASSERT(FIXED_LOCALS_OFFSET >= 2 * sizeof(sljit_uw), require_at_least_two_words); + locals_offset = FIXED_LOCALS_OFFSET; +#endif + compiler->scratches_start = locals_offset; + if (scratches > 3) + locals_offset += (scratches - 3) * sizeof(sljit_uw); compiler->saveds_start = locals_offset; if (saveds > 3) locals_offset += (saveds - 3) * sizeof(sljit_uw); compiler->locals_offset = locals_offset; +#if defined(__APPLE__) + saveds = (2 + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw); + local_size = ((locals_offset + saveds + local_size + 15) & ~15) - saveds; +#else local_size = locals_offset + ((local_size + sizeof(sljit_uw) - 1) & ~(sizeof(sljit_uw) - 1)); +#endif + compiler->local_size = local_size; #ifdef _WIN32 if (local_size > 1024) { - FAIL_IF(emit_do_imm(compiler, 0xb8 + reg_map[SLJIT_TEMPORARY_REG1], local_size)); +#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) + FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_SCRATCH_REG1], local_size)); +#else + local_size -= FIXED_LOCALS_OFFSET; + FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_SCRATCH_REG1], local_size)); + FAIL_IF(emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32, + SLJIT_LOCALS_REG, 0, SLJIT_LOCALS_REG, 0, SLJIT_IMM, FIXED_LOCALS_OFFSET)); +#endif FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack))); } #endif - compiler->local_size = local_size; SLJIT_ASSERT(local_size > 0); - return emit_non_cum_binary(compiler, 0x2b, 0x29, 0x5 << 3, 0x2d, + return emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32, SLJIT_LOCALS_REG, 0, SLJIT_LOCALS_REG, 0, SLJIT_IMM, local_size); - - return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { - int locals_offset; + sljit_si locals_offset; CHECK_ERROR_VOID(); - check_sljit_set_context(compiler, args, temporaries, saveds, local_size); + check_sljit_set_context(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; compiler->args = args; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; #endif +#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) locals_offset = 2 * sizeof(sljit_uw); - compiler->temporaries_start = locals_offset; - if (temporaries > 3) - locals_offset += (temporaries - 3) * sizeof(sljit_uw); +#else + locals_offset = FIXED_LOCALS_OFFSET; +#endif + compiler->scratches_start = locals_offset; + if (scratches > 3) + locals_offset += (scratches - 3) * sizeof(sljit_uw); compiler->saveds_start = locals_offset; if (saveds > 3) locals_offset += (saveds - 3) * sizeof(sljit_uw); compiler->locals_offset = locals_offset; +#if defined(__APPLE__) + saveds = (2 + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw); + compiler->local_size = ((locals_offset + saveds + local_size + 15) & ~15) - saveds; +#else compiler->local_size = locals_offset + ((local_size + sizeof(sljit_uw) - 1) & ~(sizeof(sljit_uw) - 1)); +#endif } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) { - int size; - sljit_ub *buf; + sljit_si size; + sljit_ub *inst; CHECK_ERROR(); check_sljit_emit_return(compiler, op, src, srcw); SLJIT_ASSERT(compiler->args >= 0); - ADJUST_LOCAL_OFFSET(src, srcw); compiler->flags_saved = 0; FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); SLJIT_ASSERT(compiler->local_size > 0); - FAIL_IF(emit_cum_binary(compiler, 0x03, 0x01, 0x0 << 3, 0x05, + FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32, SLJIT_LOCALS_REG, 0, SLJIT_LOCALS_REG, 0, SLJIT_IMM, compiler->local_size)); size = 2 + (compiler->saveds <= 3 ? compiler->saveds : 3); @@ -211,8 +234,8 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, if (compiler->args > 0) size += 2; #endif - buf = (sljit_ub*)ensure_buf(compiler, 1 + size); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + size); + FAIL_IF(!inst); INC_SIZE(size); @@ -225,14 +248,11 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, POP_REG(reg_map[TMP_REGISTER]); #if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) if (compiler->args > 2) - RETN(sizeof(sljit_w)); + RET_I16(sizeof(sljit_sw)); else RET(); #else - if (compiler->args > 0) - RETN(compiler->args * sizeof(sljit_w)); - else - RET(); + RET(); #endif return SLJIT_SUCCESS; @@ -243,16 +263,16 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, /* --------------------------------------------------------------------- */ /* Size contains the flags as well. */ -static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, +static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, sljit_si size, /* The register or immediate operand. */ - int a, sljit_w imma, + sljit_si a, sljit_sw imma, /* The general operand (not immediate). */ - int b, sljit_w immb) + sljit_si b, sljit_sw immb) { - sljit_ub *buf; + sljit_ub *inst; sljit_ub *buf_ptr; - int flags = size & ~0xf; - int inst_size; + sljit_si flags = size & ~0xf; + sljit_si inst_size; /* Both cannot be switched on. */ SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS)); @@ -263,13 +283,16 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, #if (defined SLJIT_SSE2 && SLJIT_SSE2) /* SSE2 and immediate is not possible. */ SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2)); + SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3) + && (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66) + && (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66)); #endif size &= 0xf; inst_size = size; #if (defined SLJIT_SSE2 && SLJIT_SSE2) - if (flags & EX86_PREF_F2) + if (flags & (EX86_PREF_F2 | EX86_PREF_F3)) inst_size++; #endif if (flags & EX86_PREF_66) @@ -279,13 +302,13 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, inst_size += 1; /* mod r/m byte. */ if (b & SLJIT_MEM) { if ((b & 0x0f) == SLJIT_UNUSED) - inst_size += sizeof(sljit_w); + inst_size += sizeof(sljit_sw); else if (immb != 0 && !(b & 0xf0)) { /* Immediate operand. */ if (immb <= 127 && immb >= -128) - inst_size += sizeof(sljit_b); + inst_size += sizeof(sljit_sb); else - inst_size += sizeof(sljit_w); + inst_size += sizeof(sljit_sw); } if ((b & 0xf) == SLJIT_LOCALS_REG && !(b & 0xf0)) @@ -315,29 +338,31 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, else if (flags & EX86_HALF_ARG) inst_size += sizeof(short); else - inst_size += sizeof(sljit_w); + inst_size += sizeof(sljit_sw); } else SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG); - buf = (sljit_ub*)ensure_buf(compiler, 1 + inst_size); - PTR_FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + inst_size); + PTR_FAIL_IF(!inst); /* Encoding the byte. */ INC_SIZE(inst_size); #if (defined SLJIT_SSE2 && SLJIT_SSE2) if (flags & EX86_PREF_F2) - *buf++ = 0xf2; + *inst++ = 0xf2; + if (flags & EX86_PREF_F3) + *inst++ = 0xf3; #endif if (flags & EX86_PREF_66) - *buf++ = 0x66; + *inst++ = 0x66; - buf_ptr = buf + size; + buf_ptr = inst + size; /* Encode mod/rm byte. */ if (!(flags & EX86_SHIFT_INS)) { if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM)) - *buf = (flags & EX86_BYTE_ARG) ? 0x83 : 0x81; + *inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81; if ((a & SLJIT_IMM) || (a == 0)) *buf_ptr = 0; @@ -354,19 +379,19 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, else { if (a & SLJIT_IMM) { if (imma == 1) - *buf = 0xd1; + *inst = GROUP_SHIFT_1; else - *buf = 0xc1; + *inst = GROUP_SHIFT_N; } else - *buf = 0xd3; + *inst = GROUP_SHIFT_CL; *buf_ptr = 0; } if (!(b & SLJIT_MEM)) #if (defined SLJIT_SSE2 && SLJIT_SSE2) - *buf_ptr++ |= 0xc0 + ((!(flags & EX86_SSE2)) ? reg_map[b] : b); + *buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2)) ? reg_map[b] : b); #else - *buf_ptr++ |= 0xc0 + reg_map[b]; + *buf_ptr++ |= MOD_REG + reg_map[b]; #endif else if ((b & 0x0f) != SLJIT_UNUSED) { if ((b & 0xf0) == SLJIT_UNUSED || (b & 0xf0) == (SLJIT_LOCALS_REG << 4)) { @@ -388,8 +413,8 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, if (immb <= 127 && immb >= -128) *buf_ptr++ = immb; /* 8 bit displacement. */ else { - *(sljit_w*)buf_ptr = immb; /* 32 bit displacement. */ - buf_ptr += sizeof(sljit_w); + *(sljit_sw*)buf_ptr = immb; /* 32 bit displacement. */ + buf_ptr += sizeof(sljit_sw); } } } @@ -400,8 +425,8 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, } else { *buf_ptr++ |= 0x05; - *(sljit_w*)buf_ptr = immb; /* 32 bit displacement. */ - buf_ptr += sizeof(sljit_w); + *(sljit_sw*)buf_ptr = immb; /* 32 bit displacement. */ + buf_ptr += sizeof(sljit_sw); } if (a & SLJIT_IMM) { @@ -410,45 +435,57 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, else if (flags & EX86_HALF_ARG) *(short*)buf_ptr = imma; else if (!(flags & EX86_SHIFT_INS)) - *(sljit_w*)buf_ptr = imma; + *(sljit_sw*)buf_ptr = imma; } - return !(flags & EX86_SHIFT_INS) ? buf : (buf + 1); + return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1); } /* --------------------------------------------------------------------- */ /* Call / return instructions */ /* --------------------------------------------------------------------- */ -static SLJIT_INLINE int call_with_args(struct sljit_compiler *compiler, int type) +static SLJIT_INLINE sljit_si call_with_args(struct sljit_compiler *compiler, sljit_si type) { - sljit_ub *buf; + sljit_ub *inst; #if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) - buf = (sljit_ub*)ensure_buf(compiler, type >= SLJIT_CALL3 ? 1 + 2 + 1 : 1 + 2); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, type >= SLJIT_CALL3 ? 1 + 2 + 1 : 1 + 2); + FAIL_IF(!inst); INC_SIZE(type >= SLJIT_CALL3 ? 2 + 1 : 2); if (type >= SLJIT_CALL3) - PUSH_REG(reg_map[SLJIT_TEMPORARY_REG3]); - *buf++ = 0x8b; - *buf++ = 0xc0 | (reg_map[SLJIT_TEMPORARY_REG3] << 3) | reg_map[SLJIT_TEMPORARY_REG1]; + PUSH_REG(reg_map[SLJIT_SCRATCH_REG3]); + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_map[SLJIT_SCRATCH_REG3] << 3) | reg_map[SLJIT_SCRATCH_REG1]; #else - buf = (sljit_ub*)ensure_buf(compiler, type - SLJIT_CALL0 + 1); - FAIL_IF(!buf); - INC_SIZE(type - SLJIT_CALL0); - if (type >= SLJIT_CALL3) - PUSH_REG(reg_map[SLJIT_TEMPORARY_REG3]); - if (type >= SLJIT_CALL2) - PUSH_REG(reg_map[SLJIT_TEMPORARY_REG2]); - PUSH_REG(reg_map[SLJIT_TEMPORARY_REG1]); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 * (type - SLJIT_CALL0)); + FAIL_IF(!inst); + INC_SIZE(4 * (type - SLJIT_CALL0)); + + *inst++ = MOV_rm_r; + *inst++ = MOD_DISP8 | (reg_map[SLJIT_SCRATCH_REG1] << 3) | 0x4 /* SIB */; + *inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_LOCALS_REG]; + *inst++ = 0; + if (type >= SLJIT_CALL2) { + *inst++ = MOV_rm_r; + *inst++ = MOD_DISP8 | (reg_map[SLJIT_SCRATCH_REG2] << 3) | 0x4 /* SIB */; + *inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_LOCALS_REG]; + *inst++ = sizeof(sljit_sw); + } + if (type >= SLJIT_CALL3) { + *inst++ = MOV_rm_r; + *inst++ = MOD_DISP8 | (reg_map[SLJIT_SCRATCH_REG3] << 3) | 0x4 /* SIB */; + *inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_LOCALS_REG]; + *inst++ = 2 * sizeof(sljit_sw); + } #endif return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw) { - sljit_ub *buf; + sljit_ub *inst; CHECK_ERROR(); check_sljit_emit_fast_enter(compiler, dst, dstw); @@ -456,33 +493,30 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compil CHECK_EXTRA_REGS(dst, dstw, (void)0); - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!buf); + /* For UNUSED dst. Uncommon, but possible. */ + if (dst == SLJIT_UNUSED) + dst = TMP_REGISTER; + + if (dst <= TMP_REGISTER) { + /* Unused dest is possible here. */ + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); INC_SIZE(1); POP_REG(reg_map[dst]); return SLJIT_SUCCESS; } - else if (dst & SLJIT_MEM) { - buf = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); - FAIL_IF(!buf); - *buf++ = 0x8f; - return SLJIT_SUCCESS; - } - /* For UNUSED dst. Uncommon, but possible. */ - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!buf); - - INC_SIZE(1); - POP_REG(reg_map[TMP_REGISTER]); + /* Memory. */ + inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); + FAIL_IF(!inst); + *inst++ = POP_rm; return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw) { - sljit_ub *buf; + sljit_ub *inst; CHECK_ERROR(); check_sljit_emit_fast_return(compiler, src, srcw); @@ -490,32 +524,32 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compi CHECK_EXTRA_REGS(src, srcw, (void)0); - if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1); - FAIL_IF(!buf); + if (src <= TMP_REGISTER) { + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1); + FAIL_IF(!inst); INC_SIZE(1 + 1); PUSH_REG(reg_map[src]); } else if (src & SLJIT_MEM) { - buf = emit_x86_instruction(compiler, 1, 0, 0, src, srcw); - FAIL_IF(!buf); - *buf++ = 0xff; - *buf |= 6 << 3; + inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw); + FAIL_IF(!inst); + *inst++ = GROUP_FF; + *inst |= PUSH_rm; - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); INC_SIZE(1); } else { /* SLJIT_IMM. */ - buf = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1); + FAIL_IF(!inst); INC_SIZE(5 + 1); - *buf++ = 0x68; - *(sljit_w*)buf = srcw; - buf += sizeof(sljit_w); + *inst++ = PUSH_i32; + *(sljit_sw*)inst = srcw; + inst += sizeof(sljit_sw); } RET(); diff --git a/src/3rd/pcre/sjx8664.c b/src/3rd/pcre/sjx8664.c index 480cebc785..28f04fddd8 100644 --- a/src/3rd/pcre/sjx8664.c +++ b/src/3rd/pcre/sjx8664.c @@ -26,75 +26,76 @@ /* x86 64-bit arch dependent functions. */ -static int emit_load_imm64(struct sljit_compiler *compiler, int reg, sljit_w imm) +static sljit_si emit_load_imm64(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm) { - sljit_ub *buf; + sljit_ub *inst; - buf = (sljit_ub*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_w)); - FAIL_IF(!buf); - INC_SIZE(2 + sizeof(sljit_w)); - *buf++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B); - *buf++ = 0xb8 + (reg_map[reg] & 0x7); - *(sljit_w*)buf = imm; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw)); + FAIL_IF(!inst); + INC_SIZE(2 + sizeof(sljit_sw)); + *inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B); + *inst++ = MOV_r_i32 + (reg_map[reg] & 0x7); + *(sljit_sw*)inst = imm; return SLJIT_SUCCESS; } -static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, int type) +static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_si type) { if (type < SLJIT_JUMP) { + /* Invert type. */ *code_ptr++ = get_jump_code(type ^ 0x1) - 0x10; *code_ptr++ = 10 + 3; } SLJIT_COMPILE_ASSERT(reg_map[TMP_REG3] == 9, tmp3_is_9_first); *code_ptr++ = REX_W | REX_B; - *code_ptr++ = 0xb8 + 1; + *code_ptr++ = MOV_r_i32 + 1; jump->addr = (sljit_uw)code_ptr; if (jump->flags & JUMP_LABEL) jump->flags |= PATCH_MD; else - *(sljit_w*)code_ptr = jump->u.target; + *(sljit_sw*)code_ptr = jump->u.target; - code_ptr += sizeof(sljit_w); + code_ptr += sizeof(sljit_sw); *code_ptr++ = REX_B; - *code_ptr++ = 0xff; - *code_ptr++ = (type >= SLJIT_FAST_CALL) ? 0xd1 /* call */ : 0xe1 /* jmp */; + *code_ptr++ = GROUP_FF; + *code_ptr++ = (type >= SLJIT_FAST_CALL) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1); return code_ptr; } -static sljit_ub* generate_fixed_jump(sljit_ub *code_ptr, sljit_w addr, int type) +static sljit_ub* generate_fixed_jump(sljit_ub *code_ptr, sljit_sw addr, sljit_si type) { - sljit_w delta = addr - ((sljit_w)code_ptr + 1 + sizeof(sljit_hw)); + sljit_sw delta = addr - ((sljit_sw)code_ptr + 1 + sizeof(sljit_si)); if (delta <= SLJIT_W(0x7fffffff) && delta >= SLJIT_W(-0x80000000)) { - *code_ptr++ = (type == 2) ? 0xe8 /* call */ : 0xe9 /* jmp */; - *(sljit_w*)code_ptr = delta; + *code_ptr++ = (type == 2) ? CALL_i32 : JMP_i32; + *(sljit_sw*)code_ptr = delta; } else { SLJIT_COMPILE_ASSERT(reg_map[TMP_REG3] == 9, tmp3_is_9_second); *code_ptr++ = REX_W | REX_B; - *code_ptr++ = 0xb8 + 1; - *(sljit_w*)code_ptr = addr; - code_ptr += sizeof(sljit_w); + *code_ptr++ = MOV_r_i32 + 1; + *(sljit_sw*)code_ptr = addr; + code_ptr += sizeof(sljit_sw); *code_ptr++ = REX_B; - *code_ptr++ = 0xff; - *code_ptr++ = (type == 2) ? 0xd1 /* call */ : 0xe1 /* jmp */; + *code_ptr++ = GROUP_FF; + *code_ptr++ = (type == 2) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1); } return code_ptr; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { - int size, pushed_size; - sljit_ub *buf; + sljit_si size, pushed_size; + sljit_ub *inst; CHECK_ERROR(); - check_sljit_emit_enter(compiler, args, temporaries, saveds, local_size); + check_sljit_emit_enter(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; compiler->flags_saved = 0; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) @@ -103,38 +104,38 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i size = saveds; /* Including the return address saved by the call instruction. */ - pushed_size = (saveds + 1) * sizeof(sljit_w); + pushed_size = (saveds + 1) * sizeof(sljit_sw); #ifndef _WIN64 if (saveds >= 2) size += saveds - 1; #else if (saveds >= 4) size += saveds - 3; - if (temporaries >= 5) { + if (scratches >= 5) { size += (5 - 4) * 2; - pushed_size += sizeof(sljit_w); + pushed_size += sizeof(sljit_sw); } #endif size += args * 3; if (size > 0) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + size); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + size); + FAIL_IF(!inst); INC_SIZE(size); if (saveds >= 5) { SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_EREG2] >= 8, saved_ereg2_is_hireg); - *buf++ = REX_B; + *inst++ = REX_B; PUSH_REG(reg_lmap[SLJIT_SAVED_EREG2]); } if (saveds >= 4) { SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_EREG1] >= 8, saved_ereg1_is_hireg); - *buf++ = REX_B; + *inst++ = REX_B; PUSH_REG(reg_lmap[SLJIT_SAVED_EREG1]); } if (saveds >= 3) { #ifndef _WIN64 SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_REG3] >= 8, saved_reg3_is_hireg); - *buf++ = REX_B; + *inst++ = REX_B; #else SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_REG3] < 8, saved_reg3_is_loreg); #endif @@ -143,7 +144,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i if (saveds >= 2) { #ifndef _WIN64 SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_REG2] >= 8, saved_reg2_is_hireg); - *buf++ = REX_B; + *inst++ = REX_B; #else SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SAVED_REG2] < 8, saved_reg2_is_loreg); #endif @@ -154,44 +155,44 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i PUSH_REG(reg_lmap[SLJIT_SAVED_REG1]); } #ifdef _WIN64 - if (temporaries >= 5) { + if (scratches >= 5) { SLJIT_COMPILE_ASSERT(reg_map[SLJIT_TEMPORARY_EREG2] >= 8, temporary_ereg2_is_hireg); - *buf++ = REX_B; + *inst++ = REX_B; PUSH_REG(reg_lmap[SLJIT_TEMPORARY_EREG2]); } #endif #ifndef _WIN64 if (args > 0) { - *buf++ = REX_W; - *buf++ = 0x8b; - *buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG1] << 3) | 0x7; + *inst++ = REX_W; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG1] << 3) | 0x7 /* rdi */; } if (args > 1) { - *buf++ = REX_W | REX_R; - *buf++ = 0x8b; - *buf++ = 0xc0 | (reg_lmap[SLJIT_SAVED_REG2] << 3) | 0x6; + *inst++ = REX_W | REX_R; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_lmap[SLJIT_SAVED_REG2] << 3) | 0x6 /* rsi */; } if (args > 2) { - *buf++ = REX_W | REX_R; - *buf++ = 0x8b; - *buf++ = 0xc0 | (reg_lmap[SLJIT_SAVED_REG3] << 3) | 0x2; + *inst++ = REX_W | REX_R; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_lmap[SLJIT_SAVED_REG3] << 3) | 0x2 /* rdx */; } #else if (args > 0) { - *buf++ = REX_W; - *buf++ = 0x8b; - *buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG1] << 3) | 0x1; + *inst++ = REX_W; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG1] << 3) | 0x1 /* rcx */; } if (args > 1) { - *buf++ = REX_W; - *buf++ = 0x8b; - *buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG2] << 3) | 0x2; + *inst++ = REX_W; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG2] << 3) | 0x2 /* rdx */; } if (args > 2) { - *buf++ = REX_W | REX_B; - *buf++ = 0x8b; - *buf++ = 0xc0 | (reg_map[SLJIT_SAVED_REG3] << 3) | 0x0; + *inst++ = REX_W | REX_B; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_map[SLJIT_SAVED_REG3] << 3) | 0x0 /* r8 */; } #endif } @@ -201,101 +202,124 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_enter(struct sljit_compiler *compiler, i #ifdef _WIN64 if (local_size > 1024) { /* Allocate stack for the callback, which grows the stack. */ - buf = (sljit_ub*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!buf); - INC_SIZE(4); - *buf++ = REX_W; - *buf++ = 0x83; - *buf++ = 0xc0 | (5 << 3) | 4; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 + (3 + sizeof(sljit_si))); + FAIL_IF(!inst); + INC_SIZE(4 + (3 + sizeof(sljit_si))); + *inst++ = REX_W; + *inst++ = GROUP_BINARY_83; + *inst++ = MOD_REG | SUB | 4; /* Pushed size must be divisible by 8. */ SLJIT_ASSERT(!(pushed_size & 0x7)); if (pushed_size & 0x8) { - *buf++ = 5 * sizeof(sljit_w); - local_size -= 5 * sizeof(sljit_w); + *inst++ = 5 * sizeof(sljit_sw); + local_size -= 5 * sizeof(sljit_sw); } else { - *buf++ = 4 * sizeof(sljit_w); - local_size -= 4 * sizeof(sljit_w); + *inst++ = 4 * sizeof(sljit_sw); + local_size -= 4 * sizeof(sljit_sw); } - FAIL_IF(emit_load_imm64(compiler, SLJIT_TEMPORARY_REG1, local_size)); + /* Second instruction */ + SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SCRATCH_REG1] < 8, temporary_reg1_is_loreg); + *inst++ = REX_W; + *inst++ = MOV_rm_i32; + *inst++ = MOD_REG | reg_lmap[SLJIT_SCRATCH_REG1]; + *(sljit_si*)inst = local_size; +#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) + compiler->skip_checks = 1; +#endif FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack))); } #endif SLJIT_ASSERT(local_size > 0); if (local_size <= 127) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4); + FAIL_IF(!inst); INC_SIZE(4); - *buf++ = REX_W; - *buf++ = 0x83; - *buf++ = 0xc0 | (5 << 3) | 4; - *buf++ = local_size; + *inst++ = REX_W; + *inst++ = GROUP_BINARY_83; + *inst++ = MOD_REG | SUB | 4; + *inst++ = local_size; } else { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 7); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 7); + FAIL_IF(!inst); INC_SIZE(7); - *buf++ = REX_W; - *buf++ = 0x81; - *buf++ = 0xc0 | (5 << 3) | 4; - *(sljit_hw*)buf = local_size; - buf += sizeof(sljit_hw); + *inst++ = REX_W; + *inst++ = GROUP_BINARY_81; + *inst++ = MOD_REG | SUB | 4; + *(sljit_si*)inst = local_size; + inst += sizeof(sljit_si); } +#ifdef _WIN64 + /* Save xmm6 with MOVAPS instruction. */ + inst = (sljit_ub*)ensure_buf(compiler, 1 + 5); + FAIL_IF(!inst); + INC_SIZE(5); + *inst++ = GROUP_0F; + *(sljit_si*)inst = 0x20247429; +#endif return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, int args, int temporaries, int saveds, int local_size) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, sljit_si args, sljit_si scratches, sljit_si saveds, sljit_si local_size) { - int pushed_size; + sljit_si pushed_size; CHECK_ERROR_VOID(); - check_sljit_set_context(compiler, args, temporaries, saveds, local_size); + check_sljit_set_context(compiler, args, scratches, saveds, local_size); - compiler->temporaries = temporaries; + compiler->scratches = scratches; compiler->saveds = saveds; #if (defined SLJIT_DEBUG && SLJIT_DEBUG) compiler->logical_local_size = local_size; #endif /* Including the return address saved by the call instruction. */ - pushed_size = (saveds + 1) * sizeof(sljit_w); + pushed_size = (saveds + 1) * sizeof(sljit_sw); #ifdef _WIN64 - if (temporaries >= 5) - pushed_size += sizeof(sljit_w); + if (scratches >= 5) + pushed_size += sizeof(sljit_sw); #endif compiler->local_size = ((local_size + FIXED_LOCALS_OFFSET + pushed_size + 16 - 1) & ~(16 - 1)) - pushed_size; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, int op, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) { - int size; - sljit_ub *buf; + sljit_si size; + sljit_ub *inst; CHECK_ERROR(); check_sljit_emit_return(compiler, op, src, srcw); - ADJUST_LOCAL_OFFSET(src, srcw); compiler->flags_saved = 0; FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); +#ifdef _WIN64 + /* Restore xmm6 with MOVAPS instruction. */ + inst = (sljit_ub*)ensure_buf(compiler, 1 + 5); + FAIL_IF(!inst); + INC_SIZE(5); + *inst++ = GROUP_0F; + *(sljit_si*)inst = 0x20247428; +#endif SLJIT_ASSERT(compiler->local_size > 0); if (compiler->local_size <= 127) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4); + FAIL_IF(!inst); INC_SIZE(4); - *buf++ = REX_W; - *buf++ = 0x83; - *buf++ = 0xc0 | (0 << 3) | 4; - *buf = compiler->local_size; + *inst++ = REX_W; + *inst++ = GROUP_BINARY_83; + *inst++ = MOD_REG | ADD | 4; + *inst = compiler->local_size; } else { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 7); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 7); + FAIL_IF(!inst); INC_SIZE(7); - *buf++ = REX_W; - *buf++ = 0x81; - *buf++ = 0xc0 | (0 << 3) | 4; - *(sljit_hw*)buf = compiler->local_size; + *inst++ = REX_W; + *inst++ = GROUP_BINARY_81; + *inst++ = MOD_REG | ADD | 4; + *(sljit_si*)inst = compiler->local_size; } size = 1 + compiler->saveds; @@ -305,17 +329,17 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, #else if (compiler->saveds >= 4) size += compiler->saveds - 3; - if (compiler->temporaries >= 5) + if (compiler->scratches >= 5) size += (5 - 4) * 2; #endif - buf = (sljit_ub*)ensure_buf(compiler, 1 + size); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + size); + FAIL_IF(!inst); INC_SIZE(size); #ifdef _WIN64 - if (compiler->temporaries >= 5) { - *buf++ = REX_B; + if (compiler->scratches >= 5) { + *inst++ = REX_B; POP_REG(reg_lmap[SLJIT_TEMPORARY_EREG2]); } #endif @@ -323,22 +347,22 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, POP_REG(reg_map[SLJIT_SAVED_REG1]); if (compiler->saveds >= 2) { #ifndef _WIN64 - *buf++ = REX_B; + *inst++ = REX_B; #endif POP_REG(reg_lmap[SLJIT_SAVED_REG2]); } if (compiler->saveds >= 3) { #ifndef _WIN64 - *buf++ = REX_B; + *inst++ = REX_B; #endif POP_REG(reg_lmap[SLJIT_SAVED_REG3]); } if (compiler->saveds >= 4) { - *buf++ = REX_B; + *inst++ = REX_B; POP_REG(reg_lmap[SLJIT_SAVED_EREG1]); } if (compiler->saveds >= 5) { - *buf++ = REX_B; + *inst++ = REX_B; POP_REG(reg_lmap[SLJIT_SAVED_EREG2]); } @@ -350,39 +374,32 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_return(struct sljit_compiler *compiler, /* Operators */ /* --------------------------------------------------------------------- */ -static int emit_do_imm32(struct sljit_compiler *compiler, sljit_ub rex, sljit_ub opcode, sljit_w imm) +static sljit_si emit_do_imm32(struct sljit_compiler *compiler, sljit_ub rex, sljit_ub opcode, sljit_sw imm) { - sljit_ub *buf; + sljit_ub *inst; + sljit_si length = 1 + (rex ? 1 : 0) + sizeof(sljit_si); - if (rex != 0) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_hw)); - FAIL_IF(!buf); - INC_SIZE(2 + sizeof(sljit_hw)); - *buf++ = rex; - *buf++ = opcode; - *(sljit_hw*)buf = imm; - } - else { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_hw)); - FAIL_IF(!buf); - INC_SIZE(1 + sizeof(sljit_hw)); - *buf++ = opcode; - *(sljit_hw*)buf = imm; - } + inst = (sljit_ub*)ensure_buf(compiler, 1 + length); + FAIL_IF(!inst); + INC_SIZE(length); + if (rex) + *inst++ = rex; + *inst++ = opcode; + *(sljit_si*)inst = imm; return SLJIT_SUCCESS; } -static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, +static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, sljit_si size, /* The register or immediate operand. */ - int a, sljit_w imma, + sljit_si a, sljit_sw imma, /* The general operand (not immediate). */ - int b, sljit_w immb) + sljit_si b, sljit_sw immb) { - sljit_ub *buf; + sljit_ub *inst; sljit_ub *buf_ptr; sljit_ub rex = 0; - int flags = size & ~0xf; - int inst_size; + sljit_si flags = size & ~0xf; + sljit_si inst_size; /* The immediate operand must be 32 bit. */ SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma)); @@ -395,6 +412,9 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, #if (defined SLJIT_SSE2 && SLJIT_SSE2) /* SSE2 and immediate is not possible. */ SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2)); + SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3) + && (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66) + && (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66)); #endif size &= 0xf; @@ -416,7 +436,7 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, rex |= REX; #if (defined SLJIT_SSE2 && SLJIT_SSE2) - if (flags & EX86_PREF_F2) + if (flags & (EX86_PREF_F2 | EX86_PREF_F3)) inst_size++; #endif if (flags & EX86_PREF_66) @@ -426,16 +446,16 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, inst_size += 1; /* mod r/m byte. */ if (b & SLJIT_MEM) { if ((b & 0x0f) == SLJIT_UNUSED) - inst_size += 1 + sizeof(sljit_hw); /* SIB byte required to avoid RIP based addressing. */ + inst_size += 1 + sizeof(sljit_si); /* SIB byte required to avoid RIP based addressing. */ else { if (reg_map[b & 0x0f] >= 8) rex |= REX_B; if (immb != 0 && !(b & 0xf0)) { /* Immediate operand. */ if (immb <= 127 && immb >= -128) - inst_size += sizeof(sljit_b); + inst_size += sizeof(sljit_sb); else - inst_size += sizeof(sljit_hw); + inst_size += sizeof(sljit_si); } } @@ -475,7 +495,7 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, else if (flags & EX86_HALF_ARG) inst_size += sizeof(short); else - inst_size += sizeof(sljit_hw); + inst_size += sizeof(sljit_si); } else { SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG); @@ -492,25 +512,27 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, if (rex) inst_size++; - buf = (sljit_ub*)ensure_buf(compiler, 1 + inst_size); - PTR_FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + inst_size); + PTR_FAIL_IF(!inst); /* Encoding the byte. */ INC_SIZE(inst_size); #if (defined SLJIT_SSE2 && SLJIT_SSE2) if (flags & EX86_PREF_F2) - *buf++ = 0xf2; + *inst++ = 0xf2; + if (flags & EX86_PREF_F3) + *inst++ = 0xf3; #endif if (flags & EX86_PREF_66) - *buf++ = 0x66; + *inst++ = 0x66; if (rex) - *buf++ = rex; - buf_ptr = buf + size; + *inst++ = rex; + buf_ptr = inst + size; /* Encode mod/rm byte. */ if (!(flags & EX86_SHIFT_INS)) { if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM)) - *buf = (flags & EX86_BYTE_ARG) ? 0x83 : 0x81; + *inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81; if ((a & SLJIT_IMM) || (a == 0)) *buf_ptr = 0; @@ -527,19 +549,19 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, else { if (a & SLJIT_IMM) { if (imma == 1) - *buf = 0xd1; + *inst = GROUP_SHIFT_1; else - *buf = 0xc1; + *inst = GROUP_SHIFT_N; } else - *buf = 0xd3; + *inst = GROUP_SHIFT_CL; *buf_ptr = 0; } if (!(b & SLJIT_MEM)) #if (defined SLJIT_SSE2 && SLJIT_SSE2) - *buf_ptr++ |= 0xc0 + ((!(flags & EX86_SSE2)) ? reg_lmap[b] : b); + *buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2)) ? reg_lmap[b] : b); #else - *buf_ptr++ |= 0xc0 + reg_lmap[b]; + *buf_ptr++ |= MOD_REG + reg_lmap[b]; #endif else if ((b & 0x0f) != SLJIT_UNUSED) { if ((b & 0xf0) == SLJIT_UNUSED || (b & 0xf0) == (SLJIT_LOCALS_REG << 4)) { @@ -561,8 +583,8 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, if (immb <= 127 && immb >= -128) *buf_ptr++ = immb; /* 8 bit displacement. */ else { - *(sljit_hw*)buf_ptr = immb; /* 32 bit displacement. */ - buf_ptr += sizeof(sljit_hw); + *(sljit_si*)buf_ptr = immb; /* 32 bit displacement. */ + buf_ptr += sizeof(sljit_si); } } } @@ -574,8 +596,8 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, else { *buf_ptr++ |= 0x04; *buf_ptr++ = 0x25; - *(sljit_hw*)buf_ptr = immb; /* 32 bit displacement. */ - buf_ptr += sizeof(sljit_hw); + *(sljit_si*)buf_ptr = immb; /* 32 bit displacement. */ + buf_ptr += sizeof(sljit_si); } if (a & SLJIT_IMM) { @@ -584,55 +606,55 @@ static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, int size, else if (flags & EX86_HALF_ARG) *(short*)buf_ptr = imma; else if (!(flags & EX86_SHIFT_INS)) - *(sljit_hw*)buf_ptr = imma; + *(sljit_si*)buf_ptr = imma; } - return !(flags & EX86_SHIFT_INS) ? buf : (buf + 1); + return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1); } /* --------------------------------------------------------------------- */ /* Call / return instructions */ /* --------------------------------------------------------------------- */ -static SLJIT_INLINE int call_with_args(struct sljit_compiler *compiler, int type) +static SLJIT_INLINE sljit_si call_with_args(struct sljit_compiler *compiler, sljit_si type) { - sljit_ub *buf; + sljit_ub *inst; #ifndef _WIN64 - SLJIT_COMPILE_ASSERT(reg_map[SLJIT_TEMPORARY_REG2] == 6 && reg_map[SLJIT_TEMPORARY_REG1] < 8 && reg_map[SLJIT_TEMPORARY_REG3] < 8, args_registers); + SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SCRATCH_REG2] == 6 && reg_map[SLJIT_SCRATCH_REG1] < 8 && reg_map[SLJIT_SCRATCH_REG3] < 8, args_registers); - buf = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6)); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6)); + FAIL_IF(!inst); INC_SIZE((type < SLJIT_CALL3) ? 3 : 6); if (type >= SLJIT_CALL3) { - *buf++ = REX_W; - *buf++ = 0x8b; - *buf++ = 0xc0 | (0x2 << 3) | reg_lmap[SLJIT_TEMPORARY_REG3]; + *inst++ = REX_W; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (0x2 /* rdx */ << 3) | reg_lmap[SLJIT_SCRATCH_REG3]; } - *buf++ = REX_W; - *buf++ = 0x8b; - *buf++ = 0xc0 | (0x7 << 3) | reg_lmap[SLJIT_TEMPORARY_REG1]; + *inst++ = REX_W; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (0x7 /* rdi */ << 3) | reg_lmap[SLJIT_SCRATCH_REG1]; #else - SLJIT_COMPILE_ASSERT(reg_map[SLJIT_TEMPORARY_REG2] == 2 && reg_map[SLJIT_TEMPORARY_REG1] < 8 && reg_map[SLJIT_TEMPORARY_REG3] < 8, args_registers); + SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SCRATCH_REG2] == 2 && reg_map[SLJIT_SCRATCH_REG1] < 8 && reg_map[SLJIT_SCRATCH_REG3] < 8, args_registers); - buf = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6)); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6)); + FAIL_IF(!inst); INC_SIZE((type < SLJIT_CALL3) ? 3 : 6); if (type >= SLJIT_CALL3) { - *buf++ = REX_W | REX_R; - *buf++ = 0x8b; - *buf++ = 0xc0 | (0x0 << 3) | reg_lmap[SLJIT_TEMPORARY_REG3]; + *inst++ = REX_W | REX_R; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (0x0 /* r8 */ << 3) | reg_lmap[SLJIT_SCRATCH_REG3]; } - *buf++ = REX_W; - *buf++ = 0x8b; - *buf++ = 0xc0 | (0x1 << 3) | reg_lmap[SLJIT_TEMPORARY_REG1]; + *inst++ = REX_W; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (0x1 /* rcx */ << 3) | reg_lmap[SLJIT_SCRATCH_REG1]; #endif return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compiler, int dst, sljit_w dstw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw) { - sljit_ub *buf; + sljit_ub *inst; CHECK_ERROR(); check_sljit_emit_fast_enter(compiler, dst, dstw); @@ -642,36 +664,34 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_enter(struct sljit_compiler *compil if (dst == SLJIT_UNUSED) dst = TMP_REGISTER; - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) { + if (dst <= TMP_REGISTER) { if (reg_map[dst] < 8) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!buf); - + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); INC_SIZE(1); POP_REG(reg_lmap[dst]); + return SLJIT_SUCCESS; } - else { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!buf); - INC_SIZE(2); - *buf++ = REX_B; - POP_REG(reg_lmap[dst]); - } - } - else if (dst & SLJIT_MEM) { - /* REX_W is not necessary (src is not immediate). */ - compiler->mode32 = 1; - buf = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); - FAIL_IF(!buf); - *buf++ = 0x8f; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 2); + FAIL_IF(!inst); + INC_SIZE(2); + *inst++ = REX_B; + POP_REG(reg_lmap[dst]); + return SLJIT_SUCCESS; } + + /* REX_W is not necessary (src is not immediate). */ + compiler->mode32 = 1; + inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); + FAIL_IF(!inst); + *inst++ = POP_rm; return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compiler, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw) { - sljit_ub *buf; + sljit_ub *inst; CHECK_ERROR(); check_sljit_emit_fast_return(compiler, src, srcw); @@ -682,45 +702,45 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compi src = TMP_REGISTER; } - if (src >= SLJIT_TEMPORARY_REG1 && src <= TMP_REGISTER) { + if (src <= TMP_REGISTER) { if (reg_map[src] < 8) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1); + FAIL_IF(!inst); INC_SIZE(1 + 1); PUSH_REG(reg_lmap[src]); } else { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 2 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + 1); + FAIL_IF(!inst); INC_SIZE(2 + 1); - *buf++ = REX_B; + *inst++ = REX_B; PUSH_REG(reg_lmap[src]); } } else if (src & SLJIT_MEM) { /* REX_W is not necessary (src is not immediate). */ compiler->mode32 = 1; - buf = emit_x86_instruction(compiler, 1, 0, 0, src, srcw); - FAIL_IF(!buf); - *buf++ = 0xff; - *buf |= 6 << 3; + inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw); + FAIL_IF(!inst); + *inst++ = GROUP_FF; + *inst |= PUSH_rm; - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); INC_SIZE(1); } else { SLJIT_ASSERT(IS_HALFWORD(srcw)); /* SLJIT_IMM. */ - buf = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1); + FAIL_IF(!inst); INC_SIZE(5 + 1); - *buf++ = 0x68; - *(sljit_hw*)buf = srcw; - buf += sizeof(sljit_hw); + *inst++ = PUSH_i32; + *(sljit_si*)inst = srcw; + inst += sizeof(sljit_si); } RET(); @@ -732,12 +752,12 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fast_return(struct sljit_compiler *compi /* Extend input */ /* --------------------------------------------------------------------- */ -static int emit_mov_int(struct sljit_compiler *compiler, int sign, - int dst, sljit_w dstw, - int src, sljit_w srcw) +static sljit_si emit_mov_int(struct sljit_compiler *compiler, sljit_si sign, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - sljit_ub* code; - int dst_r; + sljit_ub* inst; + sljit_si dst_r; compiler->mode32 = 0; @@ -745,32 +765,32 @@ static int emit_mov_int(struct sljit_compiler *compiler, int sign, return SLJIT_SUCCESS; /* Empty instruction. */ if (src & SLJIT_IMM) { - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { + if (dst <= TMP_REGISTER) { if (sign || ((sljit_uw)srcw <= 0x7fffffff)) { - code = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_w)(sljit_i)srcw, dst, dstw); - FAIL_IF(!code); - *code = 0xc7; + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_si)srcw, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm_i32; return SLJIT_SUCCESS; } return emit_load_imm64(compiler, dst, srcw); } compiler->mode32 = 1; - code = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_w)(sljit_i)srcw, dst, dstw); - FAIL_IF(!code); - *code = 0xc7; + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_si)srcw, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm_i32; compiler->mode32 = 0; return SLJIT_SUCCESS; } - dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_SAVED_REG3) ? dst : TMP_REGISTER; + dst_r = (dst <= TMP_REGISTER) ? dst : TMP_REGISTER; - if ((dst & SLJIT_MEM) && (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_SAVED_REG3)) + if ((dst & SLJIT_MEM) && (src <= TMP_REGISTER)) dst_r = src; else { if (sign) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw); - FAIL_IF(!code); - *code++ = 0x63; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw); + FAIL_IF(!inst); + *inst++ = MOVSXD_r_rm; } else { compiler->mode32 = 1; FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw)); @@ -780,9 +800,9 @@ static int emit_mov_int(struct sljit_compiler *compiler, int sign, if (dst & SLJIT_MEM) { compiler->mode32 = 1; - code = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x89; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm_r; compiler->mode32 = 0; } diff --git a/src/3rd/pcre/sjx86c.c b/src/3rd/pcre/sjx86c.c index d380175eb1..922e8edda7 100644 --- a/src/3rd/pcre/sjx86c.c +++ b/src/3rd/pcre/sjx86c.c @@ -24,7 +24,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() +SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name(void) { return "x86" SLJIT_CPUINFO; } @@ -67,17 +67,17 @@ SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() #define TMP_REGISTER (SLJIT_NO_REGISTERS + 1) static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 2] = { - 0, 0, 2, 1, 0, 0, 3, 6, 7, 0, 0, 4, 5 + 0, 0, 2, 1, 0, 0, 3, 6, 7, 0, 0, 4, 5 }; #define CHECK_EXTRA_REGS(p, w, do) \ if (p >= SLJIT_TEMPORARY_EREG1 && p <= SLJIT_TEMPORARY_EREG2) { \ - w = compiler->temporaries_start + (p - SLJIT_TEMPORARY_EREG1) * sizeof(sljit_w); \ + w = compiler->scratches_start + (p - SLJIT_TEMPORARY_EREG1) * sizeof(sljit_sw); \ p = SLJIT_MEM1(SLJIT_LOCALS_REG); \ do; \ } \ else if (p >= SLJIT_SAVED_EREG1 && p <= SLJIT_SAVED_EREG2) { \ - w = compiler->saveds_start + (p - SLJIT_SAVED_EREG1) * sizeof(sljit_w); \ + w = compiler->saveds_start + (p - SLJIT_SAVED_EREG1) * sizeof(sljit_sw); \ p = SLJIT_MEM1(SLJIT_LOCALS_REG); \ do; \ } @@ -95,20 +95,20 @@ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 2] = { #ifndef _WIN64 /* 1st passed in rdi, 2nd argument passed in rsi, 3rd in rdx. */ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 4] = { - 0, 0, 6, 1, 8, 11, 3, 15, 14, 13, 12, 4, 2, 7, 9 + 0, 0, 6, 1, 8, 11, 3, 15, 14, 13, 12, 4, 2, 7, 9 }; /* low-map. reg_map & 0x7. */ static SLJIT_CONST sljit_ub reg_lmap[SLJIT_NO_REGISTERS + 4] = { - 0, 0, 6, 1, 0, 3, 3, 7, 6, 5, 4, 4, 2, 7, 1 + 0, 0, 6, 1, 0, 3, 3, 7, 6, 5, 4, 4, 2, 7, 1 }; #else /* 1st passed in rcx, 2nd argument passed in rdx, 3rd in r8. */ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 4] = { - 0, 0, 2, 1, 11, 13, 3, 6, 7, 14, 15, 4, 10, 8, 9 + 0, 0, 2, 1, 11, 13, 3, 6, 7, 14, 15, 4, 10, 8, 9 }; /* low-map. reg_map & 0x7. */ static SLJIT_CONST sljit_ub reg_lmap[SLJIT_NO_REGISTERS + 4] = { - 0, 0, 2, 1, 3, 5, 3, 6, 7, 6, 7, 4, 2, 0, 1 + 0, 0, 2, 1, 3, 5, 3, 6, 7, 6, 7, 4, 2, 0, 1 }; #endif @@ -118,9 +118,6 @@ static SLJIT_CONST sljit_ub reg_lmap[SLJIT_NO_REGISTERS + 4] = { #define REX_B 0x41 #define REX 0x40 -typedef unsigned int sljit_uhw; -typedef int sljit_hw; - #define IS_HALFWORD(x) ((x) <= 0x7fffffffll && (x) >= -0x80000000ll) #define NOT_HALFWORD(x) ((x) > 0x7fffffffll || (x) < -0x80000000ll) @@ -129,7 +126,7 @@ typedef int sljit_hw; #endif /* SLJIT_CONFIG_X86_32 */ #if (defined SLJIT_SSE2 && SLJIT_SSE2) -#define TMP_FREG (SLJIT_FLOAT_REG4 + 1) +#define TMP_FREG (0) #endif /* Size flags for emit_x86_instruction: */ @@ -142,108 +139,278 @@ typedef int sljit_hw; #define EX86_PREF_66 0x0400 #if (defined SLJIT_SSE2 && SLJIT_SSE2) -#define EX86_PREF_F2 0x0800 -#define EX86_SSE2 0x1000 +#define EX86_SSE2 0x0800 +#define EX86_PREF_F2 0x1000 +#define EX86_PREF_F3 0x2000 #endif -#define INC_SIZE(s) (*buf++ = (s), compiler->size += (s)) -#define INC_CSIZE(s) (*code++ = (s), compiler->size += (s)) +/* --------------------------------------------------------------------- */ +/* Instrucion forms */ +/* --------------------------------------------------------------------- */ -#define PUSH_REG(r) (*buf++ = (0x50 + (r))) -#define POP_REG(r) (*buf++ = (0x58 + (r))) -#define RET() (*buf++ = (0xc3)) -#define RETN(n) (*buf++ = (0xc2), *buf++ = n, *buf++ = 0) +#define ADD (/* BINARY */ 0 << 3) +#define ADD_EAX_i32 0x05 +#define ADD_r_rm 0x03 +#define ADD_rm_r 0x01 +#define ADDSD_x_xm 0x58 +#define ADC (/* BINARY */ 2 << 3) +#define ADC_EAX_i32 0x15 +#define ADC_r_rm 0x13 +#define ADC_rm_r 0x11 +#define AND (/* BINARY */ 4 << 3) +#define AND_EAX_i32 0x25 +#define AND_r_rm 0x23 +#define AND_rm_r 0x21 +#define ANDPD_x_xm 0x54 +#define BSR_r_rm (/* GROUP_0F */ 0xbd) +#define CALL_i32 0xe8 +#define CALL_rm (/* GROUP_FF */ 2 << 3) +#define CDQ 0x99 +#define CMOVNE_r_rm (/* GROUP_0F */ 0x45) +#define CMP (/* BINARY */ 7 << 3) +#define CMP_EAX_i32 0x3d +#define CMP_r_rm 0x3b +#define CMP_rm_r 0x39 +#define DIV (/* GROUP_F7 */ 6 << 3) +#define DIVSD_x_xm 0x5e +#define INT3 0xcc +#define IDIV (/* GROUP_F7 */ 7 << 3) +#define IMUL (/* GROUP_F7 */ 5 << 3) +#define IMUL_r_rm (/* GROUP_0F */ 0xaf) +#define IMUL_r_rm_i8 0x6b +#define IMUL_r_rm_i32 0x69 +#define JE_i8 0x74 +#define JMP_i8 0xeb +#define JMP_i32 0xe9 +#define JMP_rm (/* GROUP_FF */ 4 << 3) +#define LEA_r_m 0x8d +#define MOV_r_rm 0x8b +#define MOV_r_i32 0xb8 +#define MOV_rm_r 0x89 +#define MOV_rm_i32 0xc7 +#define MOV_rm8_i8 0xc6 +#define MOV_rm8_r8 0x88 +#define MOVSD_x_xm 0x10 +#define MOVSD_xm_x 0x11 +#define MOVSXD_r_rm 0x63 +#define MOVSX_r_rm8 (/* GROUP_0F */ 0xbe) +#define MOVSX_r_rm16 (/* GROUP_0F */ 0xbf) +#define MOVZX_r_rm8 (/* GROUP_0F */ 0xb6) +#define MOVZX_r_rm16 (/* GROUP_0F */ 0xb7) +#define MUL (/* GROUP_F7 */ 4 << 3) +#define MULSD_x_xm 0x59 +#define NEG_rm (/* GROUP_F7 */ 3 << 3) +#define NOP 0x90 +#define NOT_rm (/* GROUP_F7 */ 2 << 3) +#define OR (/* BINARY */ 1 << 3) +#define OR_r_rm 0x0b +#define OR_EAX_i32 0x0d +#define OR_rm_r 0x09 +#define OR_rm8_r8 0x08 +#define POP_r 0x58 +#define POP_rm 0x8f +#define POPF 0x9d +#define PUSH_i32 0x68 +#define PUSH_r 0x50 +#define PUSH_rm (/* GROUP_FF */ 6 << 3) +#define PUSHF 0x9c +#define RET_near 0xc3 +#define RET_i16 0xc2 +#define SBB (/* BINARY */ 3 << 3) +#define SBB_EAX_i32 0x1d +#define SBB_r_rm 0x1b +#define SBB_rm_r 0x19 +#define SAR (/* SHIFT */ 7 << 3) +#define SHL (/* SHIFT */ 4 << 3) +#define SHR (/* SHIFT */ 5 << 3) +#define SUB (/* BINARY */ 5 << 3) +#define SUB_EAX_i32 0x2d +#define SUB_r_rm 0x2b +#define SUB_rm_r 0x29 +#define SUBSD_x_xm 0x5c +#define TEST_EAX_i32 0xa9 +#define TEST_rm_r 0x85 +#define UCOMISD_x_xm 0x2e +#define XCHG_EAX_r 0x90 +#define XCHG_r_rm 0x87 +#define XOR (/* BINARY */ 6 << 3) +#define XOR_EAX_i32 0x35 +#define XOR_r_rm 0x33 +#define XOR_rm_r 0x31 +#define XORPD_x_xm 0x57 + +#define GROUP_0F 0x0f +#define GROUP_F7 0xf7 +#define GROUP_FF 0xff +#define GROUP_BINARY_81 0x81 +#define GROUP_BINARY_83 0x83 +#define GROUP_SHIFT_1 0xd1 +#define GROUP_SHIFT_N 0xc1 +#define GROUP_SHIFT_CL 0xd3 + +#define MOD_REG 0xc0 +#define MOD_DISP8 0x40 + +#define INC_SIZE(s) (*inst++ = (s), compiler->size += (s)) + +#define PUSH_REG(r) (*inst++ = (PUSH_r + (r))) +#define POP_REG(r) (*inst++ = (POP_r + (r))) +#define RET() (*inst++ = (RET_near)) +#define RET_I16(n) (*inst++ = (RET_i16), *inst++ = n, *inst++ = 0) /* r32, r/m32 */ -#define MOV_RM(mod, reg, rm) (*buf++ = (0x8b), *buf++ = (mod) << 6 | (reg) << 3 | (rm)) +#define MOV_RM(mod, reg, rm) (*inst++ = (MOV_r_rm), *inst++ = (mod) << 6 | (reg) << 3 | (rm)) -static sljit_ub get_jump_code(int type) +/* Multithreading does not affect these static variables, since they store + built-in CPU features. Therefore they can be overwritten by different threads + if they detect the CPU features in the same time. */ +#if (defined SLJIT_SSE2 && SLJIT_SSE2) && (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) +static sljit_si cpu_has_sse2 = -1; +#endif +static sljit_si cpu_has_cmov = -1; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#include +#endif + +static void get_cpu_features(void) +{ + sljit_ui features; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + int CPUInfo[4]; + __cpuid(CPUInfo, 1); + features = (sljit_ui)CPUInfo[3]; + +#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C) + + /* AT&T syntax. */ + __asm__ ( + "movl $0x1, %%eax\n" +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + /* On x86-32, there is no red zone, so this + should work (no need for a local variable). */ + "push %%ebx\n" +#endif + "cpuid\n" +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + "pop %%ebx\n" +#endif + "movl %%edx, %0\n" + : "=g" (features) + : +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + : "%eax", "%ecx", "%edx" +#else + : "%rax", "%rbx", "%rcx", "%rdx" +#endif + ); + +#else /* _MSC_VER && _MSC_VER >= 1400 */ + + /* Intel syntax. */ + __asm { + mov eax, 1 + cpuid + mov features, edx + } + +#endif /* _MSC_VER && _MSC_VER >= 1400 */ + +#if (defined SLJIT_SSE2 && SLJIT_SSE2) && (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) + cpu_has_sse2 = (features >> 26) & 0x1; +#endif + cpu_has_cmov = (features >> 15) & 0x1; +} + +static sljit_ub get_jump_code(sljit_si type) { switch (type) { case SLJIT_C_EQUAL: case SLJIT_C_FLOAT_EQUAL: - return 0x84; + return 0x84 /* je */; case SLJIT_C_NOT_EQUAL: case SLJIT_C_FLOAT_NOT_EQUAL: - return 0x85; + return 0x85 /* jne */; case SLJIT_C_LESS: case SLJIT_C_FLOAT_LESS: - return 0x82; + return 0x82 /* jc */; case SLJIT_C_GREATER_EQUAL: case SLJIT_C_FLOAT_GREATER_EQUAL: - return 0x83; + return 0x83 /* jae */; case SLJIT_C_GREATER: case SLJIT_C_FLOAT_GREATER: - return 0x87; + return 0x87 /* jnbe */; case SLJIT_C_LESS_EQUAL: case SLJIT_C_FLOAT_LESS_EQUAL: - return 0x86; + return 0x86 /* jbe */; case SLJIT_C_SIG_LESS: - return 0x8c; + return 0x8c /* jl */; case SLJIT_C_SIG_GREATER_EQUAL: - return 0x8d; + return 0x8d /* jnl */; case SLJIT_C_SIG_GREATER: - return 0x8f; + return 0x8f /* jnle */; case SLJIT_C_SIG_LESS_EQUAL: - return 0x8e; + return 0x8e /* jle */; case SLJIT_C_OVERFLOW: case SLJIT_C_MUL_OVERFLOW: - return 0x80; + return 0x80 /* jo */; case SLJIT_C_NOT_OVERFLOW: case SLJIT_C_MUL_NOT_OVERFLOW: - return 0x81; + return 0x81 /* jno */; - case SLJIT_C_FLOAT_NAN: - return 0x8a; + case SLJIT_C_FLOAT_UNORDERED: + return 0x8a /* jp */; - case SLJIT_C_FLOAT_NOT_NAN: - return 0x8b; + case SLJIT_C_FLOAT_ORDERED: + return 0x8b /* jpo */; } return 0; } -static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, int type); +static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_si type); #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) -static sljit_ub* generate_fixed_jump(sljit_ub *code_ptr, sljit_w addr, int type); +static sljit_ub* generate_fixed_jump(sljit_ub *code_ptr, sljit_sw addr, sljit_si type); #endif -static sljit_ub* generate_near_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_ub *code, int type) +static sljit_ub* generate_near_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_ub *code, sljit_si type) { - int short_jump; + sljit_si short_jump; sljit_uw label_addr; if (jump->flags & JUMP_LABEL) label_addr = (sljit_uw)(code + jump->u.label->size); else label_addr = jump->u.target; - short_jump = (sljit_w)(label_addr - (jump->addr + 2)) >= -128 && (sljit_w)(label_addr - (jump->addr + 2)) <= 127; + short_jump = (sljit_sw)(label_addr - (jump->addr + 2)) >= -128 && (sljit_sw)(label_addr - (jump->addr + 2)) <= 127; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((sljit_w)(label_addr - (jump->addr + 1)) > 0x7fffffffll || (sljit_w)(label_addr - (jump->addr + 1)) < -0x80000000ll) + if ((sljit_sw)(label_addr - (jump->addr + 1)) > 0x7fffffffll || (sljit_sw)(label_addr - (jump->addr + 1)) < -0x80000000ll) return generate_far_jump_code(jump, code_ptr, type); #endif if (type == SLJIT_JUMP) { if (short_jump) - *code_ptr++ = 0xeb; + *code_ptr++ = JMP_i8; else - *code_ptr++ = 0xe9; + *code_ptr++ = JMP_i32; jump->addr++; } else if (type >= SLJIT_FAST_CALL) { short_jump = 0; - *code_ptr++ = 0xe8; + *code_ptr++ = CALL_i32; jump->addr++; } else if (short_jump) { @@ -251,20 +418,20 @@ static sljit_ub* generate_near_jump_code(struct sljit_jump *jump, sljit_ub *code jump->addr++; } else { - *code_ptr++ = 0x0f; + *code_ptr++ = GROUP_0F; *code_ptr++ = get_jump_code(type); jump->addr += 2; } if (short_jump) { jump->flags |= PATCH_MB; - code_ptr += sizeof(sljit_b); + code_ptr += sizeof(sljit_sb); } else { jump->flags |= PATCH_MW; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - code_ptr += sizeof(sljit_w); + code_ptr += sizeof(sljit_sw); #else - code_ptr += sizeof(sljit_hw); + code_ptr += sizeof(sljit_si); #endif } @@ -323,19 +490,19 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil label = label->next; } else if (*buf_ptr == 1) { - const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_w); + const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_sw); const_ = const_->next; } else { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - *code_ptr++ = (*buf_ptr == 2) ? 0xe8 /* call */ : 0xe9 /* jmp */; + *code_ptr++ = (*buf_ptr == 2) ? CALL_i32 : JMP_i32; buf_ptr++; - *(sljit_w*)code_ptr = *(sljit_w*)buf_ptr - ((sljit_w)code_ptr + sizeof(sljit_w)); - code_ptr += sizeof(sljit_w); - buf_ptr += sizeof(sljit_w) - 1; + *(sljit_sw*)code_ptr = *(sljit_sw*)buf_ptr - ((sljit_sw)code_ptr + sizeof(sljit_sw)); + code_ptr += sizeof(sljit_sw); + buf_ptr += sizeof(sljit_sw) - 1; #else - code_ptr = generate_fixed_jump(code_ptr, *(sljit_w*)(buf_ptr + 1), *buf_ptr); - buf_ptr += sizeof(sljit_w); + code_ptr = generate_fixed_jump(code_ptr, *(sljit_sw*)(buf_ptr + 1), *buf_ptr); + buf_ptr += sizeof(sljit_sw); #endif } buf_ptr++; @@ -352,29 +519,29 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil jump = compiler->jumps; while (jump) { if (jump->flags & PATCH_MB) { - SLJIT_ASSERT((sljit_w)(jump->u.label->addr - (jump->addr + sizeof(sljit_b))) >= -128 && (sljit_w)(jump->u.label->addr - (jump->addr + sizeof(sljit_b))) <= 127); - *(sljit_ub*)jump->addr = (sljit_ub)(jump->u.label->addr - (jump->addr + sizeof(sljit_b))); + SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_sb))) >= -128 && (sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_sb))) <= 127); + *(sljit_ub*)jump->addr = (sljit_ub)(jump->u.label->addr - (jump->addr + sizeof(sljit_sb))); } else if (jump->flags & PATCH_MW) { if (jump->flags & JUMP_LABEL) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - *(sljit_w*)jump->addr = (sljit_w)(jump->u.label->addr - (jump->addr + sizeof(sljit_w))); + *(sljit_sw*)jump->addr = (sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_sw))); #else - SLJIT_ASSERT((sljit_w)(jump->u.label->addr - (jump->addr + sizeof(sljit_hw))) >= -0x80000000ll && (sljit_w)(jump->u.label->addr - (jump->addr + sizeof(sljit_hw))) <= 0x7fffffffll); - *(sljit_hw*)jump->addr = (sljit_hw)(jump->u.label->addr - (jump->addr + sizeof(sljit_hw))); + SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_si))) >= -0x80000000ll && (sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_si))) <= 0x7fffffffll); + *(sljit_si*)jump->addr = (sljit_si)(jump->u.label->addr - (jump->addr + sizeof(sljit_si))); #endif } else { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - *(sljit_w*)jump->addr = (sljit_w)(jump->u.target - (jump->addr + sizeof(sljit_w))); + *(sljit_sw*)jump->addr = (sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_sw))); #else - SLJIT_ASSERT((sljit_w)(jump->u.target - (jump->addr + sizeof(sljit_hw))) >= -0x80000000ll && (sljit_w)(jump->u.target - (jump->addr + sizeof(sljit_hw))) <= 0x7fffffffll); - *(sljit_hw*)jump->addr = (sljit_hw)(jump->u.target - (jump->addr + sizeof(sljit_hw))); + SLJIT_ASSERT((sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_si))) >= -0x80000000ll && (sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_si))) <= 0x7fffffffll); + *(sljit_si*)jump->addr = (sljit_si)(jump->u.target - (jump->addr + sizeof(sljit_si))); #endif } } #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) else if (jump->flags & PATCH_MD) - *(sljit_w*)jump->addr = jump->u.label->addr; + *(sljit_sw*)jump->addr = jump->u.label->addr; #endif jump = jump->next; @@ -383,7 +550,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil /* Maybe we waste some space because of short jumps. */ SLJIT_ASSERT(code_ptr <= code + compiler->size); compiler->error = SLJIT_ERR_COMPILED; - compiler->executable_size = compiler->size; + compiler->executable_size = code_ptr - code; return (void*)code; } @@ -391,65 +558,65 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil /* Operators */ /* --------------------------------------------------------------------- */ -static int emit_cum_binary(struct sljit_compiler *compiler, +static sljit_si emit_cum_binary(struct sljit_compiler *compiler, sljit_ub op_rm, sljit_ub op_mr, sljit_ub op_imm, sljit_ub op_eax_imm, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w); + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w); -static int emit_non_cum_binary(struct sljit_compiler *compiler, +static sljit_si emit_non_cum_binary(struct sljit_compiler *compiler, sljit_ub op_rm, sljit_ub op_mr, sljit_ub op_imm, sljit_ub op_eax_imm, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w); + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w); -static int emit_mov(struct sljit_compiler *compiler, - int dst, sljit_w dstw, - int src, sljit_w srcw); +static sljit_si emit_mov(struct sljit_compiler *compiler, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw); -static SLJIT_INLINE int emit_save_flags(struct sljit_compiler *compiler) +static SLJIT_INLINE sljit_si emit_save_flags(struct sljit_compiler *compiler) { - sljit_ub *buf; + sljit_ub *inst; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - buf = (sljit_ub*)ensure_buf(compiler, 1 + 5); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 5); + FAIL_IF(!inst); INC_SIZE(5); #else - buf = (sljit_ub*)ensure_buf(compiler, 1 + 6); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 6); + FAIL_IF(!inst); INC_SIZE(6); - *buf++ = REX_W; + *inst++ = REX_W; #endif - *buf++ = 0x8d; /* lea esp/rsp, [esp/rsp + sizeof(sljit_w)] */ - *buf++ = 0x64; - *buf++ = 0x24; - *buf++ = (sljit_ub)sizeof(sljit_w); - *buf++ = 0x9c; /* pushfd / pushfq */ + *inst++ = LEA_r_m; /* lea esp/rsp, [esp/rsp + sizeof(sljit_sw)] */ + *inst++ = 0x64; + *inst++ = 0x24; + *inst++ = (sljit_ub)sizeof(sljit_sw); + *inst++ = PUSHF; compiler->flags_saved = 1; return SLJIT_SUCCESS; } -static SLJIT_INLINE int emit_restore_flags(struct sljit_compiler *compiler, int keep_flags) +static SLJIT_INLINE sljit_si emit_restore_flags(struct sljit_compiler *compiler, sljit_si keep_flags) { - sljit_ub *buf; + sljit_ub *inst; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - buf = (sljit_ub*)ensure_buf(compiler, 1 + 5); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 5); + FAIL_IF(!inst); INC_SIZE(5); - *buf++ = 0x9d; /* popfd */ + *inst++ = POPF; #else - buf = (sljit_ub*)ensure_buf(compiler, 1 + 6); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 6); + FAIL_IF(!inst); INC_SIZE(6); - *buf++ = 0x9d; /* popfq */ - *buf++ = REX_W; + *inst++ = POPF; + *inst++ = REX_W; #endif - *buf++ = 0x8d; /* lea esp/rsp, [esp/rsp - sizeof(sljit_w)] */ - *buf++ = 0x64; - *buf++ = 0x24; - *buf++ = (sljit_ub)-(int)sizeof(sljit_w); + *inst++ = LEA_r_m; /* lea esp/rsp, [esp/rsp - sizeof(sljit_sw)] */ + *inst++ = 0x64; + *inst++ = 0x24; + *inst++ = (sljit_ub)-(sljit_sb)sizeof(sljit_sw); compiler->flags_saved = keep_flags; return SLJIT_SUCCESS; } @@ -457,15 +624,16 @@ static SLJIT_INLINE int emit_restore_flags(struct sljit_compiler *compiler, int #ifdef _WIN32 #include -static void SLJIT_CALL sljit_grow_stack(sljit_w local_size) +static void SLJIT_CALL sljit_grow_stack(sljit_sw local_size) { /* Workaround for calling the internal _chkstk() function on Windows. This function touches all 4k pages belongs to the requested stack space, which size is passed in local_size. This is necessary on Windows where the stack can only grow in 4k steps. However, this function just burn - CPU cycles if the stack is large enough, but you don't know it in advance. - I think this is a bad design even if it has some reasons. */ - alloca(local_size); + CPU cycles if the stack is large enough. However, you don't know it in + advance, so it must always be called. I think this is a bad design in + general even if it has some reasons. */ + *(sljit_si*)alloca(local_size) = 0; } #endif @@ -476,79 +644,79 @@ static void SLJIT_CALL sljit_grow_stack(sljit_w local_size) #include "sjx8664.c" #endif -static int emit_mov(struct sljit_compiler *compiler, - int dst, sljit_w dstw, - int src, sljit_w srcw) +static sljit_si emit_mov(struct sljit_compiler *compiler, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - sljit_ub* code; + sljit_ub* inst; if (dst == SLJIT_UNUSED) { /* No destination, doesn't need to setup flags. */ if (src & SLJIT_MEM) { - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src, srcw); - FAIL_IF(!code); - *code = 0x8b; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src, srcw); + FAIL_IF(!inst); + *inst = MOV_r_rm; } return SLJIT_SUCCESS; } - if (src >= SLJIT_TEMPORARY_REG1 && src <= TMP_REGISTER) { - code = emit_x86_instruction(compiler, 1, src, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x89; + if (src <= TMP_REGISTER) { + inst = emit_x86_instruction(compiler, 1, src, 0, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm_r; return SLJIT_SUCCESS; } if (src & SLJIT_IMM) { - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) { + if (dst <= TMP_REGISTER) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - return emit_do_imm(compiler, 0xb8 + reg_map[dst], srcw); + return emit_do_imm(compiler, MOV_r_i32 + reg_map[dst], srcw); #else if (!compiler->mode32) { if (NOT_HALFWORD(srcw)) return emit_load_imm64(compiler, dst, srcw); } else - return emit_do_imm32(compiler, (reg_map[dst] >= 8) ? REX_B : 0, 0xb8 + reg_lmap[dst], srcw); + return emit_do_imm32(compiler, (reg_map[dst] >= 8) ? REX_B : 0, MOV_r_i32 + reg_lmap[dst], srcw); #endif } #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if (!compiler->mode32 && NOT_HALFWORD(srcw)) { FAIL_IF(emit_load_imm64(compiler, TMP_REG2, srcw)); - code = emit_x86_instruction(compiler, 1, TMP_REG2, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x89; + inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm_r; return SLJIT_SUCCESS; } #endif - code = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, dstw); - FAIL_IF(!code); - *code = 0xc7; + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm_i32; return SLJIT_SUCCESS; } - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) { - code = emit_x86_instruction(compiler, 1, dst, 0, src, srcw); - FAIL_IF(!code); - *code = 0x8b; + if (dst <= TMP_REGISTER) { + inst = emit_x86_instruction(compiler, 1, dst, 0, src, srcw); + FAIL_IF(!inst); + *inst = MOV_r_rm; return SLJIT_SUCCESS; } /* Memory to memory move. Requires two instruction. */ - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src, srcw); - FAIL_IF(!code); - *code = 0x8b; - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x89; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src, srcw); + FAIL_IF(!inst); + *inst = MOV_r_rm; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm_r; return SLJIT_SUCCESS; } #define EMIT_MOV(compiler, dst, dstw, src, srcw) \ FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw)); -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) { - sljit_ub *buf; + sljit_ub *inst; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - int size; + sljit_si size; #endif CHECK_ERROR(); @@ -556,16 +724,16 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int switch (GET_OPCODE(op)) { case SLJIT_BREAKPOINT: - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); INC_SIZE(1); - *buf = 0xcc; + *inst = INT3; break; case SLJIT_NOP: - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); INC_SIZE(1); - *buf = 0x90; + *inst = NOP; break; case SLJIT_UMUL: case SLJIT_SMUL: @@ -575,14 +743,14 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) #ifdef _WIN64 SLJIT_COMPILE_ASSERT( - reg_map[SLJIT_TEMPORARY_REG1] == 0 - && reg_map[SLJIT_TEMPORARY_REG2] == 2 + reg_map[SLJIT_SCRATCH_REG1] == 0 + && reg_map[SLJIT_SCRATCH_REG2] == 2 && reg_map[TMP_REGISTER] > 7, invalid_register_assignment_for_div_mul); #else SLJIT_COMPILE_ASSERT( - reg_map[SLJIT_TEMPORARY_REG1] == 0 - && reg_map[SLJIT_TEMPORARY_REG2] < 7 + reg_map[SLJIT_SCRATCH_REG1] == 0 + && reg_map[SLJIT_SCRATCH_REG2] < 7 && reg_map[TMP_REGISTER] == 2, invalid_register_assignment_for_div_mul); #endif @@ -592,87 +760,86 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op = GET_OPCODE(op); if (op == SLJIT_UDIV) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) - EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_TEMPORARY_REG2, 0); - buf = emit_x86_instruction(compiler, 1, SLJIT_TEMPORARY_REG2, 0, SLJIT_TEMPORARY_REG2, 0); + EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_SCRATCH_REG2, 0); + inst = emit_x86_instruction(compiler, 1, SLJIT_SCRATCH_REG2, 0, SLJIT_SCRATCH_REG2, 0); #else - buf = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, TMP_REGISTER, 0); + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, TMP_REGISTER, 0); #endif - FAIL_IF(!buf); - *buf = 0x33; + FAIL_IF(!inst); + *inst = XOR_r_rm; } if (op == SLJIT_SDIV) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) - EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_TEMPORARY_REG2, 0); + EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_SCRATCH_REG2, 0); #endif - /* CDQ instruction */ #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); INC_SIZE(1); - *buf = 0x99; + *inst = CDQ; #else if (compiler->mode32) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); INC_SIZE(1); - *buf = 0x99; + *inst = CDQ; } else { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 2); + FAIL_IF(!inst); INC_SIZE(2); - *buf++ = REX_W; - *buf = 0x99; + *inst++ = REX_W; + *inst = CDQ; } #endif } #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - buf = (sljit_ub*)ensure_buf(compiler, 1 + 2); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 2); + FAIL_IF(!inst); INC_SIZE(2); - *buf++ = 0xf7; - *buf = 0xc0 | ((op >= SLJIT_UDIV) ? reg_map[TMP_REGISTER] : reg_map[SLJIT_TEMPORARY_REG2]); + *inst++ = GROUP_F7; + *inst = MOD_REG | ((op >= SLJIT_UDIV) ? reg_map[TMP_REGISTER] : reg_map[SLJIT_SCRATCH_REG2]); #else #ifdef _WIN64 size = (!compiler->mode32 || op >= SLJIT_UDIV) ? 3 : 2; #else size = (!compiler->mode32) ? 3 : 2; #endif - buf = (sljit_ub*)ensure_buf(compiler, 1 + size); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + size); + FAIL_IF(!inst); INC_SIZE(size); #ifdef _WIN64 if (!compiler->mode32) - *buf++ = REX_W | ((op >= SLJIT_UDIV) ? REX_B : 0); + *inst++ = REX_W | ((op >= SLJIT_UDIV) ? REX_B : 0); else if (op >= SLJIT_UDIV) - *buf++ = REX_B; - *buf++ = 0xf7; - *buf = 0xc0 | ((op >= SLJIT_UDIV) ? reg_lmap[TMP_REGISTER] : reg_lmap[SLJIT_TEMPORARY_REG2]); + *inst++ = REX_B; + *inst++ = GROUP_F7; + *inst = MOD_REG | ((op >= SLJIT_UDIV) ? reg_lmap[TMP_REGISTER] : reg_lmap[SLJIT_SCRATCH_REG2]); #else if (!compiler->mode32) - *buf++ = REX_W; - *buf++ = 0xf7; - *buf = 0xc0 | reg_map[SLJIT_TEMPORARY_REG2]; + *inst++ = REX_W; + *inst++ = GROUP_F7; + *inst = MOD_REG | reg_map[SLJIT_SCRATCH_REG2]; #endif #endif switch (op) { case SLJIT_UMUL: - *buf |= 4 << 3; + *inst |= MUL; break; case SLJIT_SMUL: - *buf |= 5 << 3; + *inst |= IMUL; break; case SLJIT_UDIV: - *buf |= 6 << 3; + *inst |= DIV; break; case SLJIT_SDIV: - *buf |= 7 << 3; + *inst |= IDIV; break; } #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64) - EMIT_MOV(compiler, SLJIT_TEMPORARY_REG2, 0, TMP_REGISTER, 0); + EMIT_MOV(compiler, SLJIT_SCRATCH_REG2, 0, TMP_REGISTER, 0); #endif break; } @@ -682,20 +849,20 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int #define ENCODE_PREFIX(prefix) \ do { \ - code = (sljit_ub*)ensure_buf(compiler, 1 + 1); \ - FAIL_IF(!code); \ - INC_CSIZE(1); \ - *code = (prefix); \ + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); \ + FAIL_IF(!inst); \ + INC_SIZE(1); \ + *inst = (prefix); \ } while (0) -static int emit_mov_byte(struct sljit_compiler *compiler, int sign, - int dst, sljit_w dstw, - int src, sljit_w srcw) +static sljit_si emit_mov_byte(struct sljit_compiler *compiler, sljit_si sign, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - sljit_ub* code; - int dst_r; + sljit_ub* inst; + sljit_si dst_r; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - int work_r; + sljit_si work_r; #endif #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) @@ -706,22 +873,25 @@ static int emit_mov_byte(struct sljit_compiler *compiler, int sign, return SLJIT_SUCCESS; /* Empty instruction. */ if (src & SLJIT_IMM) { - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) { + if (dst <= TMP_REGISTER) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - return emit_do_imm(compiler, 0xb8 + reg_map[dst], srcw); + return emit_do_imm(compiler, MOV_r_i32 + reg_map[dst], srcw); #else - return emit_load_imm64(compiler, dst, srcw); + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, 0); + FAIL_IF(!inst); + *inst = MOV_rm_i32; + return SLJIT_SUCCESS; #endif } - code = emit_x86_instruction(compiler, 1 | EX86_BYTE_ARG | EX86_NO_REXW, SLJIT_IMM, srcw, dst, dstw); - FAIL_IF(!code); - *code = 0xc6; + inst = emit_x86_instruction(compiler, 1 | EX86_BYTE_ARG | EX86_NO_REXW, SLJIT_IMM, srcw, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm8_i8; return SLJIT_SUCCESS; } - dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) ? dst : TMP_REGISTER; + dst_r = (dst <= TMP_REGISTER) ? dst : TMP_REGISTER; - if ((dst & SLJIT_MEM) && src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS) { + if ((dst & SLJIT_MEM) && src <= TMP_REGISTER) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) if (reg_map[src] >= 4) { SLJIT_ASSERT(dst_r == TMP_REGISTER); @@ -733,35 +903,34 @@ static int emit_mov_byte(struct sljit_compiler *compiler, int sign, #endif } #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - else if (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS && reg_map[src] >= 4) { + else if (src <= TMP_REGISTER && reg_map[src] >= 4) { /* src, dst are registers. */ - SLJIT_ASSERT(dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER); + SLJIT_ASSERT(dst >= SLJIT_SCRATCH_REG1 && dst <= TMP_REGISTER); if (reg_map[dst] < 4) { if (dst != src) EMIT_MOV(compiler, dst, 0, src, 0); - code = emit_x86_instruction(compiler, 2, dst, 0, dst, 0); - FAIL_IF(!code); - *code++ = 0x0f; - *code = sign ? 0xbe : 0xb6; + inst = emit_x86_instruction(compiler, 2, dst, 0, dst, 0); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = sign ? MOVSX_r_rm8 : MOVZX_r_rm8; } else { if (dst != src) EMIT_MOV(compiler, dst, 0, src, 0); if (sign) { /* shl reg, 24 */ - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0); - FAIL_IF(!code); - *code |= 0x4 << 3; - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0); - FAIL_IF(!code); - /* shr/sar reg, 24 */ - *code |= 0x7 << 3; + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0); + FAIL_IF(!inst); + *inst |= SHL; + /* sar reg, 24 */ + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0); + FAIL_IF(!inst); + *inst |= SAR; } else { - /* and dst, 0xff */ - code = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 255, dst, 0); - FAIL_IF(!code); - *(code + 1) |= 0x4 << 3; + inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 0xff, dst, 0); + FAIL_IF(!inst); + *(inst + 1) |= AND; } } return SLJIT_SUCCESS; @@ -769,74 +938,74 @@ static int emit_mov_byte(struct sljit_compiler *compiler, int sign, #endif else { /* src can be memory addr or reg_map[src] < 4 on x86_32 architectures. */ - code = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); - FAIL_IF(!code); - *code++ = 0x0f; - *code = sign ? 0xbe : 0xb6; + inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = sign ? MOVSX_r_rm8 : MOVZX_r_rm8; } if (dst & SLJIT_MEM) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) if (dst_r == TMP_REGISTER) { /* Find a non-used register, whose reg_map[src] < 4. */ - if ((dst & 0xf) == SLJIT_TEMPORARY_REG1) { - if ((dst & 0xf0) == (SLJIT_TEMPORARY_REG2 << 4)) - work_r = SLJIT_TEMPORARY_REG3; + if ((dst & 0xf) == SLJIT_SCRATCH_REG1) { + if ((dst & 0xf0) == (SLJIT_SCRATCH_REG2 << 4)) + work_r = SLJIT_SCRATCH_REG3; else - work_r = SLJIT_TEMPORARY_REG2; + work_r = SLJIT_SCRATCH_REG2; } else { - if ((dst & 0xf0) != (SLJIT_TEMPORARY_REG1 << 4)) - work_r = SLJIT_TEMPORARY_REG1; - else if ((dst & 0xf) == SLJIT_TEMPORARY_REG2) - work_r = SLJIT_TEMPORARY_REG3; + if ((dst & 0xf0) != (SLJIT_SCRATCH_REG1 << 4)) + work_r = SLJIT_SCRATCH_REG1; + else if ((dst & 0xf) == SLJIT_SCRATCH_REG2) + work_r = SLJIT_SCRATCH_REG3; else - work_r = SLJIT_TEMPORARY_REG2; + work_r = SLJIT_SCRATCH_REG2; } - if (work_r == SLJIT_TEMPORARY_REG1) { - ENCODE_PREFIX(0x90 + reg_map[TMP_REGISTER]); + if (work_r == SLJIT_SCRATCH_REG1) { + ENCODE_PREFIX(XCHG_EAX_r + reg_map[TMP_REGISTER]); } else { - code = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0); - FAIL_IF(!code); - *code = 0x87; + inst = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0); + FAIL_IF(!inst); + *inst = XCHG_r_rm; } - code = emit_x86_instruction(compiler, 1, work_r, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x88; + inst = emit_x86_instruction(compiler, 1, work_r, 0, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm8_r8; - if (work_r == SLJIT_TEMPORARY_REG1) { - ENCODE_PREFIX(0x90 + reg_map[TMP_REGISTER]); + if (work_r == SLJIT_SCRATCH_REG1) { + ENCODE_PREFIX(XCHG_EAX_r + reg_map[TMP_REGISTER]); } else { - code = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0); - FAIL_IF(!code); - *code = 0x87; + inst = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0); + FAIL_IF(!inst); + *inst = XCHG_r_rm; } } else { - code = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x88; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm8_r8; } #else - code = emit_x86_instruction(compiler, 1 | EX86_REX | EX86_NO_REXW, dst_r, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x88; + inst = emit_x86_instruction(compiler, 1 | EX86_REX | EX86_NO_REXW, dst_r, 0, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm8_r8; #endif } return SLJIT_SUCCESS; } -static int emit_mov_half(struct sljit_compiler *compiler, int sign, - int dst, sljit_w dstw, - int src, sljit_w srcw) +static sljit_si emit_mov_half(struct sljit_compiler *compiler, sljit_si sign, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - sljit_ub* code; - int dst_r; + sljit_ub* inst; + sljit_si dst_r; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) compiler->mode32 = 0; @@ -846,193 +1015,222 @@ static int emit_mov_half(struct sljit_compiler *compiler, int sign, return SLJIT_SUCCESS; /* Empty instruction. */ if (src & SLJIT_IMM) { - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) { + if (dst <= TMP_REGISTER) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - return emit_do_imm(compiler, 0xb8 + reg_map[dst], srcw); + return emit_do_imm(compiler, MOV_r_i32 + reg_map[dst], srcw); #else - return emit_load_imm64(compiler, dst, srcw); + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, 0); + FAIL_IF(!inst); + *inst = MOV_rm_i32; + return SLJIT_SUCCESS; #endif } - code = emit_x86_instruction(compiler, 1 | EX86_HALF_ARG | EX86_NO_REXW | EX86_PREF_66, SLJIT_IMM, srcw, dst, dstw); - FAIL_IF(!code); - *code = 0xc7; + inst = emit_x86_instruction(compiler, 1 | EX86_HALF_ARG | EX86_NO_REXW | EX86_PREF_66, SLJIT_IMM, srcw, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm_i32; return SLJIT_SUCCESS; } - dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) ? dst : TMP_REGISTER; + dst_r = (dst <= TMP_REGISTER) ? dst : TMP_REGISTER; - if ((dst & SLJIT_MEM) && (src >= SLJIT_TEMPORARY_REG1 && src <= SLJIT_NO_REGISTERS)) + if ((dst & SLJIT_MEM) && src <= TMP_REGISTER) dst_r = src; else { - code = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); - FAIL_IF(!code); - *code++ = 0x0f; - *code = sign ? 0xbf : 0xb7; + inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = sign ? MOVSX_r_rm16 : MOVZX_r_rm16; } if (dst & SLJIT_MEM) { - code = emit_x86_instruction(compiler, 1 | EX86_NO_REXW | EX86_PREF_66, dst_r, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x89; + inst = emit_x86_instruction(compiler, 1 | EX86_NO_REXW | EX86_PREF_66, dst_r, 0, dst, dstw); + FAIL_IF(!inst); + *inst = MOV_rm_r; } return SLJIT_SUCCESS; } -static int emit_unary(struct sljit_compiler *compiler, int un_index, - int dst, sljit_w dstw, - int src, sljit_w srcw) +static sljit_si emit_unary(struct sljit_compiler *compiler, sljit_ub opcode, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - sljit_ub* code; + sljit_ub* inst; if (dst == SLJIT_UNUSED) { EMIT_MOV(compiler, TMP_REGISTER, 0, src, srcw); - code = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code++ = 0xf7; - *code |= (un_index) << 3; + inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst++ = GROUP_F7; + *inst |= opcode; return SLJIT_SUCCESS; } if (dst == src && dstw == srcw) { /* Same input and output */ - code = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); - FAIL_IF(!code); - *code++ = 0xf7; - *code |= (un_index) << 3; + inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); + FAIL_IF(!inst); + *inst++ = GROUP_F7; + *inst |= opcode; return SLJIT_SUCCESS; } - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { + if (dst <= TMP_REGISTER) { EMIT_MOV(compiler, dst, 0, src, srcw); - code = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); - FAIL_IF(!code); - *code++ = 0xf7; - *code |= (un_index) << 3; + inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); + FAIL_IF(!inst); + *inst++ = GROUP_F7; + *inst |= opcode; return SLJIT_SUCCESS; } EMIT_MOV(compiler, TMP_REGISTER, 0, src, srcw); - code = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code++ = 0xf7; - *code |= (un_index) << 3; + inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst++ = GROUP_F7; + *inst |= opcode; EMIT_MOV(compiler, dst, dstw, TMP_REGISTER, 0); return SLJIT_SUCCESS; } -static int emit_not_with_flags(struct sljit_compiler *compiler, - int dst, sljit_w dstw, - int src, sljit_w srcw) +static sljit_si emit_not_with_flags(struct sljit_compiler *compiler, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - sljit_ub* code; + sljit_ub* inst; if (dst == SLJIT_UNUSED) { EMIT_MOV(compiler, TMP_REGISTER, 0, src, srcw); - code = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code++ = 0xf7; - *code |= 0x2 << 3; - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code = 0x0b; + inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst++ = GROUP_F7; + *inst |= NOT_rm; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst = OR_r_rm; return SLJIT_SUCCESS; } - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { + if (dst <= TMP_REGISTER) { EMIT_MOV(compiler, dst, 0, src, srcw); - code = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); - FAIL_IF(!code); - *code++ = 0xf7; - *code |= 0x2 << 3; - code = emit_x86_instruction(compiler, 1, dst, 0, dst, 0); - FAIL_IF(!code); - *code = 0x0b; + inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw); + FAIL_IF(!inst); + *inst++ = GROUP_F7; + *inst |= NOT_rm; + inst = emit_x86_instruction(compiler, 1, dst, 0, dst, 0); + FAIL_IF(!inst); + *inst = OR_r_rm; return SLJIT_SUCCESS; } EMIT_MOV(compiler, TMP_REGISTER, 0, src, srcw); - code = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code++ = 0xf7; - *code |= 0x2 << 3; - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code = 0x0b; + inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst++ = GROUP_F7; + *inst |= NOT_rm; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst = OR_r_rm; EMIT_MOV(compiler, dst, dstw, TMP_REGISTER, 0); return SLJIT_SUCCESS; } -static int emit_clz(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +static sljit_si emit_clz(struct sljit_compiler *compiler, sljit_si op_flags, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - sljit_ub* code; - int dst_r; + sljit_ub* inst; + sljit_si dst_r; - SLJIT_UNUSED_ARG(op); + SLJIT_UNUSED_ARG(op_flags); if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) { /* Just set the zero flag. */ EMIT_MOV(compiler, TMP_REGISTER, 0, src, srcw); - code = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code++ = 0xf7; - *code |= 0x2 << 3; + inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst++ = GROUP_F7; + *inst |= NOT_rm; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 31, TMP_REGISTER, 0); + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 31, TMP_REGISTER, 0); #else - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, !(op & SLJIT_INT_OP) ? 63 : 31, TMP_REGISTER, 0); + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, !(op_flags & SLJIT_INT_OP) ? 63 : 31, TMP_REGISTER, 0); #endif - FAIL_IF(!code); - *code |= 0x5 << 3; + FAIL_IF(!inst); + *inst |= SHR; return SLJIT_SUCCESS; } if (SLJIT_UNLIKELY(src & SLJIT_IMM)) { - EMIT_MOV(compiler, TMP_REGISTER, 0, src, srcw); + EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_IMM, srcw); src = TMP_REGISTER; srcw = 0; } - code = emit_x86_instruction(compiler, 2, TMP_REGISTER, 0, src, srcw); - FAIL_IF(!code); - *code++ = 0x0f; - *code = 0xbd; + inst = emit_x86_instruction(compiler, 2, TMP_REGISTER, 0, src, srcw); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = BSR_r_rm; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) + if (dst <= TMP_REGISTER) dst_r = dst; else { /* Find an unused temporary register. */ - if ((dst & 0xf) != SLJIT_TEMPORARY_REG1 && (dst & 0xf0) != (SLJIT_TEMPORARY_REG1 << 4)) - dst_r = SLJIT_TEMPORARY_REG1; - else if ((dst & 0xf) != SLJIT_TEMPORARY_REG2 && (dst & 0xf0) != (SLJIT_TEMPORARY_REG2 << 4)) - dst_r = SLJIT_TEMPORARY_REG2; + if ((dst & 0xf) != SLJIT_SCRATCH_REG1 && (dst & 0xf0) != (SLJIT_SCRATCH_REG1 << 4)) + dst_r = SLJIT_SCRATCH_REG1; + else if ((dst & 0xf) != SLJIT_SCRATCH_REG2 && (dst & 0xf0) != (SLJIT_SCRATCH_REG2 << 4)) + dst_r = SLJIT_SCRATCH_REG2; else - dst_r = SLJIT_TEMPORARY_REG3; + dst_r = SLJIT_SCRATCH_REG3; EMIT_MOV(compiler, dst, dstw, dst_r, 0); } EMIT_MOV(compiler, dst_r, 0, SLJIT_IMM, 32 + 31); #else - dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= TMP_REGISTER) ? dst : TMP_REG2; + dst_r = (dst <= TMP_REGISTER) ? dst : TMP_REG2; compiler->mode32 = 0; - EMIT_MOV(compiler, dst_r, 0, SLJIT_IMM, !(op & SLJIT_INT_OP) ? 64 + 63 : 32 + 31); - compiler->mode32 = op & SLJIT_INT_OP; + EMIT_MOV(compiler, dst_r, 0, SLJIT_IMM, !(op_flags & SLJIT_INT_OP) ? 64 + 63 : 32 + 31); + compiler->mode32 = op_flags & SLJIT_INT_OP; #endif - code = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code++ = 0x0f; - *code = 0x45; + if (cpu_has_cmov == -1) + get_cpu_features(); + + if (cpu_has_cmov) { + inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = CMOVNE_r_rm; + } else { +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4); + FAIL_IF(!inst); + INC_SIZE(4); + + *inst++ = JE_i8; + *inst++ = 2; + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_map[dst_r] << 3) | reg_map[TMP_REGISTER]; +#else + inst = (sljit_ub*)ensure_buf(compiler, 1 + 5); + FAIL_IF(!inst); + INC_SIZE(5); + + *inst++ = JE_i8; + *inst++ = 3; + *inst++ = REX_W | (reg_map[dst_r] >= 8 ? REX_R : 0) | (reg_map[TMP_REGISTER] >= 8 ? REX_B : 0); + *inst++ = MOV_r_rm; + *inst++ = MOD_REG | (reg_lmap[dst_r] << 3) | reg_lmap[TMP_REGISTER]; +#endif + } #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - code = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 31, dst_r, 0); + inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 31, dst_r, 0); #else - code = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, !(op & SLJIT_INT_OP) ? 63 : 31, dst_r, 0); + inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, !(op_flags & SLJIT_INT_OP) ? 63 : 31, dst_r, 0); #endif - FAIL_IF(!code); - *(code + 1) |= 0x6 << 3; + FAIL_IF(!inst); + *(inst + 1) |= XOR; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) if (dst & SLJIT_MEM) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x87; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw); + FAIL_IF(!inst); + *inst = XCHG_r_rm; } #else if (dst & SLJIT_MEM) @@ -1041,17 +1239,18 @@ static int emit_clz(struct sljit_compiler *compiler, int op, return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +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) { - sljit_ub* code; - int update = 0; + sljit_ub* inst; + sljit_si update = 0; + sljit_si op_flags = GET_ALL_FLAGS(op); #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - int dst_is_ereg = 0; - int src_is_ereg = 0; + sljit_si dst_is_ereg = 0; + sljit_si src_is_ereg = 0; #else - #define src_is_ereg 0 +# define src_is_ereg 0 #endif CHECK_ERROR(); @@ -1062,41 +1261,58 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int CHECK_EXTRA_REGS(dst, dstw, dst_is_ereg = 1); CHECK_EXTRA_REGS(src, srcw, src_is_ereg = 1); #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = op & SLJIT_INT_OP; + compiler->mode32 = op_flags & SLJIT_INT_OP; #endif - if (GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOVU_SI) { - op = GET_OPCODE(op); + op = GET_OPCODE(op); + if (op >= SLJIT_MOV && op <= SLJIT_MOVU_P) { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) compiler->mode32 = 0; #endif - SLJIT_COMPILE_ASSERT(SLJIT_MOV + 7 == SLJIT_MOVU, movu_offset); + if (op_flags & SLJIT_INT_OP) { + if (src <= TMP_REGISTER && src == dst) { + if (!TYPE_CAST_NEEDED(op)) + return SLJIT_SUCCESS; + } +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (op == SLJIT_MOV_SI && (src & SLJIT_MEM)) + op = SLJIT_MOV_UI; + if (op == SLJIT_MOVU_SI && (src & SLJIT_MEM)) + op = SLJIT_MOVU_UI; + if (op == SLJIT_MOV_UI && (src & SLJIT_IMM)) + op = SLJIT_MOV_SI; + if (op == SLJIT_MOVU_UI && (src & SLJIT_IMM)) + op = SLJIT_MOVU_SI; +#endif + } + + SLJIT_COMPILE_ASSERT(SLJIT_MOV + 8 == SLJIT_MOVU, movu_offset); if (op >= SLJIT_MOVU) { update = 1; - op -= 7; + op -= 8; } if (src & SLJIT_IMM) { switch (op) { case SLJIT_MOV_UB: - srcw = (unsigned char)srcw; + srcw = (sljit_ub)srcw; break; case SLJIT_MOV_SB: - srcw = (signed char)srcw; + srcw = (sljit_sb)srcw; break; case SLJIT_MOV_UH: - srcw = (unsigned short)srcw; + srcw = (sljit_uh)srcw; break; case SLJIT_MOV_SH: - srcw = (signed short)srcw; + srcw = (sljit_sh)srcw; break; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) case SLJIT_MOV_UI: - srcw = (unsigned int)srcw; + srcw = (sljit_ui)srcw; break; case SLJIT_MOV_SI: - srcw = (signed int)srcw; + srcw = (sljit_si)srcw; break; #endif } @@ -1107,15 +1323,15 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int } if (SLJIT_UNLIKELY(update) && (src & SLJIT_MEM) && !src_is_ereg && (src & 0xf) && (srcw != 0 || (src & 0xf0) != 0)) { - code = emit_x86_instruction(compiler, 1, src & 0xf, 0, src, srcw); - FAIL_IF(!code); - *code = 0x8d; + inst = emit_x86_instruction(compiler, 1, src & 0xf, 0, src, srcw); + FAIL_IF(!inst); + *inst = LEA_r_m; src &= SLJIT_MEM | 0xf; srcw = 0; } #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (SLJIT_UNLIKELY(dst_is_ereg) && (!(op == SLJIT_MOV || op == SLJIT_MOV_UI || op == SLJIT_MOV_SI) || (src & SLJIT_MEM))) { + if (SLJIT_UNLIKELY(dst_is_ereg) && (!(op == SLJIT_MOV || op == SLJIT_MOV_UI || op == SLJIT_MOV_SI || op == SLJIT_MOV_P) || (src & SLJIT_MEM))) { SLJIT_ASSERT(dst == SLJIT_MEM1(SLJIT_LOCALS_REG)); dst = TMP_REGISTER; } @@ -1123,6 +1339,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int switch (op) { case SLJIT_MOV: + case SLJIT_MOV_P: #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) case SLJIT_MOV_UI: case SLJIT_MOV_SI: @@ -1130,23 +1347,23 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw)); break; case SLJIT_MOV_UB: - FAIL_IF(emit_mov_byte(compiler, 0, dst, dstw, src, (src & SLJIT_IMM) ? (unsigned char)srcw : srcw)); + FAIL_IF(emit_mov_byte(compiler, 0, dst, dstw, src, srcw)); break; case SLJIT_MOV_SB: - FAIL_IF(emit_mov_byte(compiler, 1, dst, dstw, src, (src & SLJIT_IMM) ? (signed char)srcw : srcw)); + FAIL_IF(emit_mov_byte(compiler, 1, dst, dstw, src, srcw)); break; case SLJIT_MOV_UH: - FAIL_IF(emit_mov_half(compiler, 0, dst, dstw, src, (src & SLJIT_IMM) ? (unsigned short)srcw : srcw)); + FAIL_IF(emit_mov_half(compiler, 0, dst, dstw, src, srcw)); break; case SLJIT_MOV_SH: - FAIL_IF(emit_mov_half(compiler, 1, dst, dstw, src, (src & SLJIT_IMM) ? (signed short)srcw : srcw)); + FAIL_IF(emit_mov_half(compiler, 1, dst, dstw, src, srcw)); break; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) case SLJIT_MOV_UI: - FAIL_IF(emit_mov_int(compiler, 0, dst, dstw, src, (src & SLJIT_IMM) ? (unsigned int)srcw : srcw)); + FAIL_IF(emit_mov_int(compiler, 0, dst, dstw, src, srcw)); break; case SLJIT_MOV_SI: - FAIL_IF(emit_mov_int(compiler, 1, dst, dstw, src, (src & SLJIT_IMM) ? (signed int)srcw : srcw)); + FAIL_IF(emit_mov_int(compiler, 1, dst, dstw, src, srcw)); break; #endif } @@ -1157,77 +1374,77 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op1(struct sljit_compiler *compiler, int #endif if (SLJIT_UNLIKELY(update) && (dst & SLJIT_MEM) && (dst & 0xf) && (dstw != 0 || (dst & 0xf0) != 0)) { - code = emit_x86_instruction(compiler, 1, dst & 0xf, 0, dst, dstw); - FAIL_IF(!code); - *code = 0x8d; + inst = emit_x86_instruction(compiler, 1, dst & 0xf, 0, dst, dstw); + FAIL_IF(!inst); + *inst = LEA_r_m; } return SLJIT_SUCCESS; } - if (SLJIT_UNLIKELY(GET_FLAGS(op))) + if (SLJIT_UNLIKELY(GET_FLAGS(op_flags))) compiler->flags_saved = 0; - switch (GET_OPCODE(op)) { + switch (op) { case SLJIT_NOT: - if (SLJIT_UNLIKELY(op & SLJIT_SET_E)) + if (SLJIT_UNLIKELY(op_flags & SLJIT_SET_E)) return emit_not_with_flags(compiler, dst, dstw, src, srcw); - return emit_unary(compiler, 0x2, dst, dstw, src, srcw); + return emit_unary(compiler, NOT_rm, dst, dstw, src, srcw); case SLJIT_NEG: - if (SLJIT_UNLIKELY(op & SLJIT_KEEP_FLAGS) && !compiler->flags_saved) + if (SLJIT_UNLIKELY(op_flags & SLJIT_KEEP_FLAGS) && !compiler->flags_saved) FAIL_IF(emit_save_flags(compiler)); - return emit_unary(compiler, 0x3, dst, dstw, src, srcw); + return emit_unary(compiler, NEG_rm, dst, dstw, src, srcw); case SLJIT_CLZ: - if (SLJIT_UNLIKELY(op & SLJIT_KEEP_FLAGS) && !compiler->flags_saved) + if (SLJIT_UNLIKELY(op_flags & SLJIT_KEEP_FLAGS) && !compiler->flags_saved) FAIL_IF(emit_save_flags(compiler)); - return emit_clz(compiler, op, dst, dstw, src, srcw); + return emit_clz(compiler, op_flags, dst, dstw, src, srcw); } return SLJIT_SUCCESS; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - #undef src_is_ereg +# undef src_is_ereg #endif } #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) -#define BINARY_IMM(_op_imm_, _op_mr_, immw, arg, argw) \ +#define BINARY_IMM(op_imm, op_mr, immw, arg, argw) \ if (IS_HALFWORD(immw) || compiler->mode32) { \ - code = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, immw, arg, argw); \ - FAIL_IF(!code); \ - *(code + 1) |= (_op_imm_); \ + inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, immw, arg, argw); \ + FAIL_IF(!inst); \ + *(inst + 1) |= (op_imm); \ } \ else { \ FAIL_IF(emit_load_imm64(compiler, TMP_REG2, immw)); \ - code = emit_x86_instruction(compiler, 1, TMP_REG2, 0, arg, argw); \ - FAIL_IF(!code); \ - *code = (_op_mr_); \ + inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, arg, argw); \ + FAIL_IF(!inst); \ + *inst = (op_mr); \ } -#define BINARY_EAX_IMM(_op_eax_imm_, immw) \ - FAIL_IF(emit_do_imm32(compiler, (!compiler->mode32) ? REX_W : 0, (_op_eax_imm_), immw)) +#define BINARY_EAX_IMM(op_eax_imm, immw) \ + FAIL_IF(emit_do_imm32(compiler, (!compiler->mode32) ? REX_W : 0, (op_eax_imm), immw)) #else -#define BINARY_IMM(_op_imm_, _op_mr_, immw, arg, argw) \ - code = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, immw, arg, argw); \ - FAIL_IF(!code); \ - *(code + 1) |= (_op_imm_); +#define BINARY_IMM(op_imm, op_mr, immw, arg, argw) \ + inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, immw, arg, argw); \ + FAIL_IF(!inst); \ + *(inst + 1) |= (op_imm); -#define BINARY_EAX_IMM(_op_eax_imm_, immw) \ - FAIL_IF(emit_do_imm(compiler, (_op_eax_imm_), immw)) +#define BINARY_EAX_IMM(op_eax_imm, immw) \ + FAIL_IF(emit_do_imm(compiler, (op_eax_imm), immw)) #endif -static int emit_cum_binary(struct sljit_compiler *compiler, +static sljit_si emit_cum_binary(struct sljit_compiler *compiler, sljit_ub op_rm, sljit_ub op_mr, sljit_ub op_imm, sljit_ub op_eax_imm, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { - sljit_ub* code; + sljit_ub* inst; if (dst == SLJIT_UNUSED) { EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); @@ -1235,9 +1452,9 @@ static int emit_cum_binary(struct sljit_compiler *compiler, BINARY_IMM(op_imm, op_mr, src2w, TMP_REGISTER, 0); } else { - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); - FAIL_IF(!code); - *code = op_rm; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); + FAIL_IF(!inst); + *inst = op_rm; } return SLJIT_SUCCESS; } @@ -1245,9 +1462,9 @@ static int emit_cum_binary(struct sljit_compiler *compiler, if (dst == src1 && dstw == src1w) { if (src2 & SLJIT_IMM) { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((dst == SLJIT_TEMPORARY_REG1) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { + if ((dst == SLJIT_SCRATCH_REG1) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { #else - if ((dst == SLJIT_TEMPORARY_REG1) && (src2w > 127 || src2w < -128)) { + if ((dst == SLJIT_SCRATCH_REG1) && (src2w > 127 || src2w < -128)) { #endif BINARY_EAX_IMM(op_eax_imm, src2w); } @@ -1255,22 +1472,22 @@ static int emit_cum_binary(struct sljit_compiler *compiler, BINARY_IMM(op_imm, op_mr, src2w, dst, dstw); } } - else if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { - code = emit_x86_instruction(compiler, 1, dst, dstw, src2, src2w); - FAIL_IF(!code); - *code = op_rm; + else if (dst <= TMP_REGISTER) { + inst = emit_x86_instruction(compiler, 1, dst, dstw, src2, src2w); + FAIL_IF(!inst); + *inst = op_rm; } - else if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= TMP_REGISTER) { - /* Special exception for sljit_emit_cond_value. */ - code = emit_x86_instruction(compiler, 1, src2, src2w, dst, dstw); - FAIL_IF(!code); - *code = op_mr; + else if (src2 <= TMP_REGISTER) { + /* Special exception for sljit_emit_op_flags. */ + inst = emit_x86_instruction(compiler, 1, src2, src2w, dst, dstw); + FAIL_IF(!inst); + *inst = op_mr; } else { EMIT_MOV(compiler, TMP_REGISTER, 0, src2, src2w); - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, dst, dstw); - FAIL_IF(!code); - *code = op_mr; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, dst, dstw); + FAIL_IF(!inst); + *inst = op_mr; } return SLJIT_SUCCESS; } @@ -1279,9 +1496,9 @@ static int emit_cum_binary(struct sljit_compiler *compiler, if (dst == src2 && dstw == src2w) { if (src1 & SLJIT_IMM) { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((dst == SLJIT_TEMPORARY_REG1) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) { + if ((dst == SLJIT_SCRATCH_REG1) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) { #else - if ((dst == SLJIT_TEMPORARY_REG1) && (src1w > 127 || src1w < -128)) { + if ((dst == SLJIT_SCRATCH_REG1) && (src1w > 127 || src1w < -128)) { #endif BINARY_EAX_IMM(op_eax_imm, src1w); } @@ -1289,35 +1506,35 @@ static int emit_cum_binary(struct sljit_compiler *compiler, BINARY_IMM(op_imm, op_mr, src1w, dst, dstw); } } - else if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { - code = emit_x86_instruction(compiler, 1, dst, dstw, src1, src1w); - FAIL_IF(!code); - *code = op_rm; + else if (dst <= TMP_REGISTER) { + inst = emit_x86_instruction(compiler, 1, dst, dstw, src1, src1w); + FAIL_IF(!inst); + *inst = op_rm; } - else if (src1 >= SLJIT_TEMPORARY_REG1 && src1 <= SLJIT_NO_REGISTERS) { - code = emit_x86_instruction(compiler, 1, src1, src1w, dst, dstw); - FAIL_IF(!code); - *code = op_mr; + else if (src1 <= TMP_REGISTER) { + inst = emit_x86_instruction(compiler, 1, src1, src1w, dst, dstw); + FAIL_IF(!inst); + *inst = op_mr; } else { EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, dst, dstw); - FAIL_IF(!code); - *code = op_mr; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, dst, dstw); + FAIL_IF(!inst); + *inst = op_mr; } return SLJIT_SUCCESS; } /* General version. */ - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { + if (dst <= TMP_REGISTER) { EMIT_MOV(compiler, dst, 0, src1, src1w); if (src2 & SLJIT_IMM) { BINARY_IMM(op_imm, op_mr, src2w, dst, 0); } else { - code = emit_x86_instruction(compiler, 1, dst, 0, src2, src2w); - FAIL_IF(!code); - *code = op_rm; + inst = emit_x86_instruction(compiler, 1, dst, 0, src2, src2w); + FAIL_IF(!inst); + *inst = op_rm; } } else { @@ -1327,9 +1544,9 @@ static int emit_cum_binary(struct sljit_compiler *compiler, BINARY_IMM(op_imm, op_mr, src2w, TMP_REGISTER, 0); } else { - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); - FAIL_IF(!code); - *code = op_rm; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); + FAIL_IF(!inst); + *inst = op_rm; } EMIT_MOV(compiler, dst, dstw, TMP_REGISTER, 0); } @@ -1337,13 +1554,13 @@ static int emit_cum_binary(struct sljit_compiler *compiler, return SLJIT_SUCCESS; } -static int emit_non_cum_binary(struct sljit_compiler *compiler, +static sljit_si emit_non_cum_binary(struct sljit_compiler *compiler, sljit_ub op_rm, sljit_ub op_mr, sljit_ub op_imm, sljit_ub op_eax_imm, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { - sljit_ub* code; + sljit_ub* inst; if (dst == SLJIT_UNUSED) { EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); @@ -1351,9 +1568,9 @@ static int emit_non_cum_binary(struct sljit_compiler *compiler, BINARY_IMM(op_imm, op_mr, src2w, TMP_REGISTER, 0); } else { - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); - FAIL_IF(!code); - *code = op_rm; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); + FAIL_IF(!inst); + *inst = op_rm; } return SLJIT_SUCCESS; } @@ -1361,9 +1578,9 @@ static int emit_non_cum_binary(struct sljit_compiler *compiler, if (dst == src1 && dstw == src1w) { if (src2 & SLJIT_IMM) { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((dst == SLJIT_TEMPORARY_REG1) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { + if ((dst == SLJIT_SCRATCH_REG1) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { #else - if ((dst == SLJIT_TEMPORARY_REG1) && (src2w > 127 || src2w < -128)) { + if ((dst == SLJIT_SCRATCH_REG1) && (src2w > 127 || src2w < -128)) { #endif BINARY_EAX_IMM(op_eax_imm, src2w); } @@ -1371,35 +1588,35 @@ static int emit_non_cum_binary(struct sljit_compiler *compiler, BINARY_IMM(op_imm, op_mr, src2w, dst, dstw); } } - else if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { - code = emit_x86_instruction(compiler, 1, dst, dstw, src2, src2w); - FAIL_IF(!code); - *code = op_rm; + else if (dst <= TMP_REGISTER) { + inst = emit_x86_instruction(compiler, 1, dst, dstw, src2, src2w); + FAIL_IF(!inst); + *inst = op_rm; } - else if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= SLJIT_NO_REGISTERS) { - code = emit_x86_instruction(compiler, 1, src2, src2w, dst, dstw); - FAIL_IF(!code); - *code = op_mr; + else if (src2 <= TMP_REGISTER) { + inst = emit_x86_instruction(compiler, 1, src2, src2w, dst, dstw); + FAIL_IF(!inst); + *inst = op_mr; } else { EMIT_MOV(compiler, TMP_REGISTER, 0, src2, src2w); - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, dst, dstw); - FAIL_IF(!code); - *code = op_mr; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, dst, dstw); + FAIL_IF(!inst); + *inst = op_mr; } return SLJIT_SUCCESS; } /* General version. */ - if ((dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) && dst != src2) { + if (dst <= TMP_REGISTER && dst != src2) { EMIT_MOV(compiler, dst, 0, src1, src1w); if (src2 & SLJIT_IMM) { BINARY_IMM(op_imm, op_mr, src2w, dst, 0); } else { - code = emit_x86_instruction(compiler, 1, dst, 0, src2, src2w); - FAIL_IF(!code); - *code = op_rm; + inst = emit_x86_instruction(compiler, 1, dst, 0, src2, src2w); + FAIL_IF(!inst); + *inst = op_rm; } } else { @@ -1409,9 +1626,9 @@ static int emit_non_cum_binary(struct sljit_compiler *compiler, BINARY_IMM(op_imm, op_mr, src2w, TMP_REGISTER, 0); } else { - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); - FAIL_IF(!code); - *code = op_rm; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); + FAIL_IF(!inst); + *inst = op_rm; } EMIT_MOV(compiler, dst, dstw, TMP_REGISTER, 0); } @@ -1419,28 +1636,28 @@ static int emit_non_cum_binary(struct sljit_compiler *compiler, return SLJIT_SUCCESS; } -static int emit_mul(struct sljit_compiler *compiler, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static sljit_si emit_mul(struct sljit_compiler *compiler, + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { - sljit_ub* code; - int dst_r; + sljit_ub* inst; + sljit_si dst_r; - dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REGISTER; + dst_r = (dst <= TMP_REGISTER) ? dst : TMP_REGISTER; /* Register destination. */ if (dst_r == src1 && !(src2 & SLJIT_IMM)) { - code = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w); - FAIL_IF(!code); - *code++ = 0x0f; - *code = 0xaf; + inst = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = IMUL_r_rm; } else if (dst_r == src2 && !(src1 & SLJIT_IMM)) { - code = emit_x86_instruction(compiler, 2, dst_r, 0, src1, src1w); - FAIL_IF(!code); - *code++ = 0x0f; - *code = 0xaf; + inst = emit_x86_instruction(compiler, 2, dst_r, 0, src1, src1w); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = IMUL_r_rm; } else if (src1 & SLJIT_IMM) { if (src2 & SLJIT_IMM) { @@ -1450,42 +1667,42 @@ static int emit_mul(struct sljit_compiler *compiler, } if (src1w <= 127 && src1w >= -128) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w); - FAIL_IF(!code); - *code = 0x6b; - code = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!code); - INC_CSIZE(1); - *code = (sljit_b)src1w; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w); + FAIL_IF(!inst); + *inst = IMUL_r_rm_i8; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); + INC_SIZE(1); + *inst = (sljit_sb)src1w; } #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) else { - code = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w); - FAIL_IF(!code); - *code = 0x69; - code = (sljit_ub*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!code); - INC_CSIZE(4); - *(sljit_w*)code = src1w; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w); + FAIL_IF(!inst); + *inst = IMUL_r_rm_i32; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4); + FAIL_IF(!inst); + INC_SIZE(4); + *(sljit_sw*)inst = src1w; } #else else if (IS_HALFWORD(src1w)) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w); - FAIL_IF(!code); - *code = 0x69; - code = (sljit_ub*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!code); - INC_CSIZE(4); - *(sljit_hw*)code = (sljit_hw)src1w; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w); + FAIL_IF(!inst); + *inst = IMUL_r_rm_i32; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4); + FAIL_IF(!inst); + INC_SIZE(4); + *(sljit_si*)inst = (sljit_si)src1w; } else { EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, src1w); if (dst_r != src2) EMIT_MOV(compiler, dst_r, 0, src2, src2w); - code = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0); - FAIL_IF(!code); - *code++ = 0x0f; - *code = 0xaf; + inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = IMUL_r_rm; } #endif } @@ -1493,42 +1710,42 @@ static int emit_mul(struct sljit_compiler *compiler, /* Note: src1 is NOT immediate. */ if (src2w <= 127 && src2w >= -128) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w); - FAIL_IF(!code); - *code = 0x6b; - code = (sljit_ub*)ensure_buf(compiler, 1 + 1); - FAIL_IF(!code); - INC_CSIZE(1); - *code = (sljit_b)src2w; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w); + FAIL_IF(!inst); + *inst = IMUL_r_rm_i8; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); + INC_SIZE(1); + *inst = (sljit_sb)src2w; } #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) else { - code = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w); - FAIL_IF(!code); - *code = 0x69; - code = (sljit_ub*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!code); - INC_CSIZE(4); - *(sljit_w*)code = src2w; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w); + FAIL_IF(!inst); + *inst = IMUL_r_rm_i32; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4); + FAIL_IF(!inst); + INC_SIZE(4); + *(sljit_sw*)inst = src2w; } #else else if (IS_HALFWORD(src2w)) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w); - FAIL_IF(!code); - *code = 0x69; - code = (sljit_ub*)ensure_buf(compiler, 1 + 4); - FAIL_IF(!code); - INC_CSIZE(4); - *(sljit_hw*)code = (sljit_hw)src2w; + inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w); + FAIL_IF(!inst); + *inst = IMUL_r_rm_i32; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4); + FAIL_IF(!inst); + INC_SIZE(4); + *(sljit_si*)inst = (sljit_si)src2w; } else { EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, src1w); if (dst_r != src1) EMIT_MOV(compiler, dst_r, 0, src1, src1w); - code = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0); - FAIL_IF(!code); - *code++ = 0x0f; - *code = 0xaf; + inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = IMUL_r_rm; } #endif } @@ -1537,10 +1754,10 @@ static int emit_mul(struct sljit_compiler *compiler, if (ADDRESSING_DEPENDS_ON(src2, dst_r)) dst_r = TMP_REGISTER; EMIT_MOV(compiler, dst_r, 0, src1, src1w); - code = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w); - FAIL_IF(!code); - *code++ = 0x0f; - *code = 0xaf; + inst = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = IMUL_r_rm; } if (dst_r == TMP_REGISTER) @@ -1549,51 +1766,53 @@ static int emit_mul(struct sljit_compiler *compiler, return SLJIT_SUCCESS; } -static int emit_lea_binary(struct sljit_compiler *compiler, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static sljit_si emit_lea_binary(struct sljit_compiler *compiler, sljit_si keep_flags, + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { - sljit_ub* code; - int dst_r, done = 0; + sljit_ub* inst; + sljit_si dst_r, done = 0; /* These cases better be left to handled by normal way. */ - if (dst == src1 && dstw == src1w) - return SLJIT_ERR_UNSUPPORTED; - if (dst == src2 && dstw == src2w) - return SLJIT_ERR_UNSUPPORTED; + if (!keep_flags) { + if (dst == src1 && dstw == src1w) + return SLJIT_ERR_UNSUPPORTED; + if (dst == src2 && dstw == src2w) + return SLJIT_ERR_UNSUPPORTED; + } - dst_r = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REGISTER; + dst_r = (dst <= TMP_REGISTER) ? dst : TMP_REGISTER; - if (src1 >= SLJIT_TEMPORARY_REG1 && src1 <= SLJIT_NO_REGISTERS) { - if ((src2 >= SLJIT_TEMPORARY_REG1 && src2 <= SLJIT_NO_REGISTERS) || src2 == TMP_REGISTER) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM2(src1, src2), 0); - FAIL_IF(!code); - *code = 0x8d; + if (src1 <= TMP_REGISTER) { + if (src2 <= TMP_REGISTER || src2 == TMP_REGISTER) { + inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM2(src1, src2), 0); + FAIL_IF(!inst); + *inst = LEA_r_m; done = 1; } #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if ((src2 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src2w))) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), (int)src2w); + inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), (sljit_si)src2w); #else if (src2 & SLJIT_IMM) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), src2w); + inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), src2w); #endif - FAIL_IF(!code); - *code = 0x8d; + FAIL_IF(!inst); + *inst = LEA_r_m; done = 1; } } - else if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= SLJIT_NO_REGISTERS) { + else if (src2 <= TMP_REGISTER) { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if ((src1 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src1w))) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), (int)src1w); + inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), (sljit_si)src1w); #else if (src1 & SLJIT_IMM) { - code = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), src1w); + inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), src1w); #endif - FAIL_IF(!code); - *code = 0x8d; + FAIL_IF(!inst); + *inst = LEA_r_m; done = 1; } } @@ -1606,37 +1825,37 @@ static int emit_lea_binary(struct sljit_compiler *compiler, return SLJIT_ERR_UNSUPPORTED; } -static int emit_cmp_binary(struct sljit_compiler *compiler, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static sljit_si emit_cmp_binary(struct sljit_compiler *compiler, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { - sljit_ub* code; + sljit_ub* inst; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (src1 == SLJIT_TEMPORARY_REG1 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { + if (src1 == SLJIT_SCRATCH_REG1 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { #else - if (src1 == SLJIT_TEMPORARY_REG1 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) { + if (src1 == SLJIT_SCRATCH_REG1 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) { #endif - BINARY_EAX_IMM(0x3d, src2w); + BINARY_EAX_IMM(CMP_EAX_i32, src2w); return SLJIT_SUCCESS; } - if (src1 >= SLJIT_TEMPORARY_REG1 && src1 <= SLJIT_NO_REGISTERS) { + if (src1 <= TMP_REGISTER) { if (src2 & SLJIT_IMM) { - BINARY_IMM(0x7 << 3, 0x39, src2w, src1, 0); + BINARY_IMM(CMP, CMP_rm_r, src2w, src1, 0); } else { - code = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w); - FAIL_IF(!code); - *code = 0x3b; + inst = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w); + FAIL_IF(!inst); + *inst = CMP_r_rm; } return SLJIT_SUCCESS; } - if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= SLJIT_NO_REGISTERS && !(src1 & SLJIT_IMM)) { - code = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w); - FAIL_IF(!code); - *code = 0x39; + if (src2 <= TMP_REGISTER && !(src1 & SLJIT_IMM)) { + inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w); + FAIL_IF(!inst); + *inst = CMP_rm_r; return SLJIT_SUCCESS; } @@ -1646,93 +1865,93 @@ static int emit_cmp_binary(struct sljit_compiler *compiler, src1 = TMP_REGISTER; src1w = 0; } - BINARY_IMM(0x7 << 3, 0x39, src2w, src1, src1w); + BINARY_IMM(CMP, CMP_rm_r, src2w, src1, src1w); } else { EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); - FAIL_IF(!code); - *code = 0x3b; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); + FAIL_IF(!inst); + *inst = CMP_r_rm; } return SLJIT_SUCCESS; } -static int emit_test_binary(struct sljit_compiler *compiler, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static sljit_si emit_test_binary(struct sljit_compiler *compiler, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { - sljit_ub* code; + sljit_ub* inst; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (src1 == SLJIT_TEMPORARY_REG1 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { + if (src1 == SLJIT_SCRATCH_REG1 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) { #else - if (src1 == SLJIT_TEMPORARY_REG1 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) { + if (src1 == SLJIT_SCRATCH_REG1 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) { #endif - BINARY_EAX_IMM(0xa9, src2w); + BINARY_EAX_IMM(TEST_EAX_i32, src2w); return SLJIT_SUCCESS; } #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if (src2 == SLJIT_TEMPORARY_REG1 && (src2 & SLJIT_IMM) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) { + if (src2 == SLJIT_SCRATCH_REG1 && (src2 & SLJIT_IMM) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) { #else - if (src2 == SLJIT_TEMPORARY_REG1 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128)) { + if (src2 == SLJIT_SCRATCH_REG1 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128)) { #endif - BINARY_EAX_IMM(0xa9, src1w); + BINARY_EAX_IMM(TEST_EAX_i32, src1w); return SLJIT_SUCCESS; } - if (src1 >= SLJIT_TEMPORARY_REG1 && src1 <= SLJIT_NO_REGISTERS) { + if (src1 <= TMP_REGISTER) { if (src2 & SLJIT_IMM) { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if (IS_HALFWORD(src2w) || compiler->mode32) { - code = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0); - FAIL_IF(!code); - *code = 0xf7; + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0); + FAIL_IF(!inst); + *inst = GROUP_F7; } else { FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w)); - code = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src1, 0); - FAIL_IF(!code); - *code = 0x85; + inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src1, 0); + FAIL_IF(!inst); + *inst = TEST_rm_r; } #else - code = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0); - FAIL_IF(!code); - *code = 0xf7; + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0); + FAIL_IF(!inst); + *inst = GROUP_F7; #endif } else { - code = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w); - FAIL_IF(!code); - *code = 0x85; + inst = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w); + FAIL_IF(!inst); + *inst = TEST_rm_r; } return SLJIT_SUCCESS; } - if (src2 >= SLJIT_TEMPORARY_REG1 && src2 <= SLJIT_NO_REGISTERS) { + if (src2 <= TMP_REGISTER) { if (src1 & SLJIT_IMM) { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if (IS_HALFWORD(src1w) || compiler->mode32) { - code = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, 0); - FAIL_IF(!code); - *code = 0xf7; + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, 0); + FAIL_IF(!inst); + *inst = GROUP_F7; } else { FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src1w)); - code = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src2, 0); - FAIL_IF(!code); - *code = 0x85; + inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src2, 0); + FAIL_IF(!inst); + *inst = TEST_rm_r; } #else - code = emit_x86_instruction(compiler, 1, src1, src1w, src2, 0); - FAIL_IF(!code); - *code = 0xf7; + inst = emit_x86_instruction(compiler, 1, src1, src1w, src2, 0); + FAIL_IF(!inst); + *inst = GROUP_F7; #endif } else { - code = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w); - FAIL_IF(!code); - *code = 0x85; + inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w); + FAIL_IF(!inst); + *inst = TEST_rm_r; } return SLJIT_SUCCESS; } @@ -1741,72 +1960,72 @@ static int emit_test_binary(struct sljit_compiler *compiler, if (src2 & SLJIT_IMM) { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if (IS_HALFWORD(src2w) || compiler->mode32) { - code = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, TMP_REGISTER, 0); - FAIL_IF(!code); - *code = 0xf7; + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst = GROUP_F7; } else { FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w)); - code = emit_x86_instruction(compiler, 1, TMP_REG2, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code = 0x85; + inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst = TEST_rm_r; } #else - code = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, TMP_REGISTER, 0); - FAIL_IF(!code); - *code = 0xf7; + inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst = GROUP_F7; #endif } else { - code = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); - FAIL_IF(!code); - *code = 0x85; + inst = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, src2, src2w); + FAIL_IF(!inst); + *inst = TEST_rm_r; } return SLJIT_SUCCESS; } -static int emit_shift(struct sljit_compiler *compiler, +static sljit_si emit_shift(struct sljit_compiler *compiler, sljit_ub mode, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { - sljit_ub* code; + sljit_ub* inst; if ((src2 & SLJIT_IMM) || (src2 == SLJIT_PREF_SHIFT_REG)) { if (dst == src1 && dstw == src1w) { - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, dstw); - FAIL_IF(!code); - *code |= mode; + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, dstw); + FAIL_IF(!inst); + *inst |= mode; return SLJIT_SUCCESS; } if (dst == SLJIT_UNUSED) { EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, TMP_REGISTER, 0); - FAIL_IF(!code); - *code |= mode; + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst |= mode; return SLJIT_SUCCESS; } if (dst == SLJIT_PREF_SHIFT_REG && src2 == SLJIT_PREF_SHIFT_REG) { EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code |= mode; + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst |= mode; EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); return SLJIT_SUCCESS; } - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) { + if (dst <= TMP_REGISTER) { EMIT_MOV(compiler, dst, 0, src1, src1w); - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, 0); - FAIL_IF(!code); - *code |= mode; + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, 0); + FAIL_IF(!inst); + *inst |= mode; return SLJIT_SUCCESS; } EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, TMP_REGISTER, 0); - FAIL_IF(!code); - *code |= mode; + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst |= mode; EMIT_MOV(compiler, dst, dstw, TMP_REGISTER, 0); return SLJIT_SUCCESS; } @@ -1814,19 +2033,19 @@ static int emit_shift(struct sljit_compiler *compiler, if (dst == SLJIT_PREF_SHIFT_REG) { EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code |= mode; + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst |= mode; EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); } - else if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS && dst != src2 && !ADDRESSING_DEPENDS_ON(src2, dst)) { + else if (dst <= TMP_REGISTER && dst != src2 && !ADDRESSING_DEPENDS_ON(src2, dst)) { if (src1 != dst) EMIT_MOV(compiler, dst, 0, src1, src1w); EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_PREF_SHIFT_REG, 0); EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, dst, 0); - FAIL_IF(!code); - *code |= mode; + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, dst, 0); + FAIL_IF(!inst); + *inst |= mode; EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); } else { @@ -1837,16 +2056,16 @@ static int emit_shift(struct sljit_compiler *compiler, EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_PREF_SHIFT_REG, 0); #else /* [esp+0] contains the flags. */ - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), sizeof(sljit_w), SLJIT_PREF_SHIFT_REG, 0); + EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), sizeof(sljit_sw), SLJIT_PREF_SHIFT_REG, 0); #endif EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); - FAIL_IF(!code); - *code |= mode; + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); + FAIL_IF(!inst); + *inst |= mode; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG2, 0); #else - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), sizeof(sljit_w)); + EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), sizeof(sljit_sw)); #endif EMIT_MOV(compiler, dst, dstw, TMP_REGISTER, 0); } @@ -1854,11 +2073,11 @@ static int emit_shift(struct sljit_compiler *compiler, return SLJIT_SUCCESS; } -static int emit_shift_with_flags(struct sljit_compiler *compiler, - sljit_ub mode, int set_flags, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +static sljit_si emit_shift_with_flags(struct sljit_compiler *compiler, + sljit_ub mode, sljit_si set_flags, + sljit_si dst, sljit_sw dstw, + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w) { /* The CPU does not set flags if the shift count is 0. */ if (src2 & SLJIT_IMM) { @@ -1872,27 +2091,27 @@ static int emit_shift_with_flags(struct sljit_compiler *compiler, if (!set_flags) return emit_mov(compiler, dst, dstw, src1, src1w); /* OR dst, src, 0 */ - return emit_cum_binary(compiler, 0x0b, 0x09, 0x1 << 3, 0x0d, + return emit_cum_binary(compiler, OR_r_rm, OR_rm_r, OR, OR_EAX_i32, dst, dstw, src1, src1w, SLJIT_IMM, 0); } if (!set_flags) return emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w); - if (!(dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS)) + if (!(dst <= TMP_REGISTER)) FAIL_IF(emit_cmp_binary(compiler, src1, src1w, SLJIT_IMM, 0)); FAIL_IF(emit_shift(compiler,mode, dst, dstw, src1, src1w, src2, src2w)); - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) + if (dst <= TMP_REGISTER) return emit_cmp_binary(compiler, dst, dstw, SLJIT_IMM, 0); return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +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); @@ -1917,14 +2136,14 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int switch (GET_OPCODE(op)) { case SLJIT_ADD: if (!GET_FLAGS(op)) { - if (emit_lea_binary(compiler, dst, dstw, src1, src1w, src2, src2w) != SLJIT_ERR_UNSUPPORTED) + if (emit_lea_binary(compiler, op & SLJIT_KEEP_FLAGS, dst, dstw, src1, src1w, src2, src2w) != SLJIT_ERR_UNSUPPORTED) return compiler->error; } else compiler->flags_saved = 0; if (SLJIT_UNLIKELY(op & SLJIT_KEEP_FLAGS) && !compiler->flags_saved) FAIL_IF(emit_save_flags(compiler)); - return emit_cum_binary(compiler, 0x03, 0x01, 0x0 << 3, 0x05, + return emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32, dst, dstw, src1, src1w, src2, src2w); case SLJIT_ADDC: if (SLJIT_UNLIKELY(compiler->flags_saved)) /* C flag must be restored. */ @@ -1933,11 +2152,11 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int FAIL_IF(emit_save_flags(compiler)); if (SLJIT_UNLIKELY(GET_FLAGS(op))) compiler->flags_saved = 0; - return emit_cum_binary(compiler, 0x13, 0x11, 0x2 << 3, 0x15, + return emit_cum_binary(compiler, ADC_r_rm, ADC_rm_r, ADC, ADC_EAX_i32, dst, dstw, src1, src1w, src2, src2w); case SLJIT_SUB: if (!GET_FLAGS(op)) { - if ((src2 & SLJIT_IMM) && emit_lea_binary(compiler, dst, dstw, src1, src1w, SLJIT_IMM, -src2w) != SLJIT_ERR_UNSUPPORTED) + if ((src2 & SLJIT_IMM) && emit_lea_binary(compiler, op & SLJIT_KEEP_FLAGS, dst, dstw, src1, src1w, SLJIT_IMM, -src2w) != SLJIT_ERR_UNSUPPORTED) return compiler->error; } else @@ -1946,7 +2165,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int FAIL_IF(emit_save_flags(compiler)); if (dst == SLJIT_UNUSED) return emit_cmp_binary(compiler, src1, src1w, src2, src2w); - return emit_non_cum_binary(compiler, 0x2b, 0x29, 0x5 << 3, 0x2d, + return emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32, dst, dstw, src1, src1w, src2, src2w); case SLJIT_SUBC: if (SLJIT_UNLIKELY(compiler->flags_saved)) /* C flag must be restored. */ @@ -1955,36 +2174,36 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int FAIL_IF(emit_save_flags(compiler)); if (SLJIT_UNLIKELY(GET_FLAGS(op))) compiler->flags_saved = 0; - return emit_non_cum_binary(compiler, 0x1b, 0x19, 0x3 << 3, 0x1d, + return emit_non_cum_binary(compiler, SBB_r_rm, SBB_rm_r, SBB, SBB_EAX_i32, dst, dstw, src1, src1w, src2, src2w); case SLJIT_MUL: return emit_mul(compiler, dst, dstw, src1, src1w, src2, src2w); case SLJIT_AND: if (dst == SLJIT_UNUSED) return emit_test_binary(compiler, src1, src1w, src2, src2w); - return emit_cum_binary(compiler, 0x23, 0x21, 0x4 << 3, 0x25, + return emit_cum_binary(compiler, AND_r_rm, AND_rm_r, AND, AND_EAX_i32, dst, dstw, src1, src1w, src2, src2w); case SLJIT_OR: - return emit_cum_binary(compiler, 0x0b, 0x09, 0x1 << 3, 0x0d, + return emit_cum_binary(compiler, OR_r_rm, OR_rm_r, OR, OR_EAX_i32, dst, dstw, src1, src1w, src2, src2w); case SLJIT_XOR: - return emit_cum_binary(compiler, 0x33, 0x31, 0x6 << 3, 0x35, + return emit_cum_binary(compiler, XOR_r_rm, XOR_rm_r, XOR, XOR_EAX_i32, dst, dstw, src1, src1w, src2, src2w); case SLJIT_SHL: - return emit_shift_with_flags(compiler, 0x4 << 3, GET_FLAGS(op), + return emit_shift_with_flags(compiler, SHL, GET_FLAGS(op), dst, dstw, src1, src1w, src2, src2w); case SLJIT_LSHR: - return emit_shift_with_flags(compiler, 0x5 << 3, GET_FLAGS(op), + return emit_shift_with_flags(compiler, SHR, GET_FLAGS(op), dst, dstw, src1, src1w, src2, src2w); case SLJIT_ASHR: - return emit_shift_with_flags(compiler, 0x7 << 3, GET_FLAGS(op), + return emit_shift_with_flags(compiler, SAR, GET_FLAGS(op), dst, dstw, src1, src1w, src2, src2w); } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg) { check_sljit_get_register_index(reg); #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) @@ -1995,19 +2214,25 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg) return reg_map[reg]; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler, - void *instruction, int size) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg) { - sljit_ub *buf; + check_sljit_get_float_register_index(reg); + return reg; +} + +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, + void *instruction, sljit_si size) +{ + sljit_ub *inst; CHECK_ERROR(); check_sljit_emit_op_custom(compiler, instruction, size); SLJIT_ASSERT(size > 0 && size < 16); - buf = (sljit_ub*)ensure_buf(compiler, 1 + size); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + size); + FAIL_IF(!inst); INC_SIZE(size); - SLJIT_MEMMOVE(buf, instruction, size); + SLJIT_MEMMOVE(inst, instruction, size); return SLJIT_SUCCESS; } @@ -2018,107 +2243,82 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compile #if (defined SLJIT_SSE2 && SLJIT_SSE2) /* Alignment + 2 * 16 bytes. */ -static sljit_i sse2_data[3 + 4 + 4]; -static sljit_i *sse2_buffer; +static sljit_si sse2_data[3 + (4 + 4) * 2]; +static sljit_si *sse2_buffer; -static void init_compiler() +static void init_compiler(void) { - sse2_buffer = (sljit_i*)(((sljit_uw)sse2_data + 15) & ~0xf); - sse2_buffer[0] = 0; - sse2_buffer[1] = 0x80000000; - sse2_buffer[4] = 0xffffffff; - sse2_buffer[5] = 0x7fffffff; + sse2_buffer = (sljit_si*)(((sljit_uw)sse2_data + 15) & ~0xf); + /* Single precision constants. */ + sse2_buffer[0] = 0x80000000; + sse2_buffer[4] = 0x7fffffff; + /* Double precision constants. */ + sse2_buffer[8] = 0; + sse2_buffer[9] = 0x80000000; + sse2_buffer[12] = 0xffffffff; + sse2_buffer[13] = 0x7fffffff; } #endif -SLJIT_API_FUNC_ATTRIBUTE int sljit_is_fpu_available(void) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void) { #if (defined SLJIT_SSE2 && SLJIT_SSE2) #if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) - static int sse2_available = -1; - int features; - - if (sse2_available != -1) - return sse2_available; - -#ifdef __GNUC__ - /* AT&T syntax. */ - asm ( - "pushl %%ebx\n" - "movl $0x1, %%eax\n" - "cpuid\n" - "popl %%ebx\n" - "movl %%edx, %0\n" - : "=g" (features) - : - : "%eax", "%ecx", "%edx" - ); -#elif defined(_MSC_VER) || defined(__BORLANDC__) - /* Intel syntax. */ - __asm { - mov eax, 1 - push ebx - cpuid - pop ebx - mov features, edx - } -#else - #error "SLJIT_DETECT_SSE2 is not implemented for this C compiler" -#endif - sse2_available = (features >> 26) & 0x1; - return sse2_available; -#else + if (cpu_has_sse2 == -1) + get_cpu_features(); + return cpu_has_sse2; +#else /* SLJIT_DETECT_SSE2 */ return 1; -#endif -#else +#endif /* SLJIT_DETECT_SSE2 */ +#else /* SLJIT_SSE2 */ return 0; #endif } #if (defined SLJIT_SSE2 && SLJIT_SSE2) -static int emit_sse2(struct sljit_compiler *compiler, sljit_ub opcode, - int xmm1, int xmm2, sljit_w xmm2w) +static sljit_si emit_sse2(struct sljit_compiler *compiler, sljit_ub opcode, + sljit_si single, sljit_si xmm1, sljit_si xmm2, sljit_sw xmm2w) { - sljit_ub *buf; + sljit_ub *inst; - buf = emit_x86_instruction(compiler, 2 | EX86_PREF_F2 | EX86_SSE2, xmm1, 0, xmm2, xmm2w); - FAIL_IF(!buf); - *buf++ = 0x0f; - *buf = opcode; + inst = emit_x86_instruction(compiler, 2 | (single ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, xmm1, 0, xmm2, xmm2w); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = opcode; return SLJIT_SUCCESS; } -static int emit_sse2_logic(struct sljit_compiler *compiler, sljit_ub opcode, - int xmm1, int xmm2, sljit_w xmm2w) +static sljit_si emit_sse2_logic(struct sljit_compiler *compiler, sljit_ub opcode, + sljit_si pref66, sljit_si xmm1, sljit_si xmm2, sljit_sw xmm2w) { - sljit_ub *buf; + sljit_ub *inst; - buf = emit_x86_instruction(compiler, 2 | EX86_PREF_66 | EX86_SSE2, xmm1, 0, xmm2, xmm2w); - FAIL_IF(!buf); - *buf++ = 0x0f; - *buf = opcode; + inst = emit_x86_instruction(compiler, 2 | (pref66 ? EX86_PREF_66 : 0) | EX86_SSE2, xmm1, 0, xmm2, xmm2w); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = opcode; return SLJIT_SUCCESS; } -static SLJIT_INLINE int emit_sse2_load(struct sljit_compiler *compiler, - int dst, int src, sljit_w srcw) +static SLJIT_INLINE sljit_si emit_sse2_load(struct sljit_compiler *compiler, + sljit_si single, sljit_si dst, sljit_si src, sljit_sw srcw) { - return emit_sse2(compiler, 0x10, dst, src, srcw); + return emit_sse2(compiler, MOVSD_x_xm, single, dst, src, srcw); } -static SLJIT_INLINE int emit_sse2_store(struct sljit_compiler *compiler, - int dst, sljit_w dstw, int src) +static SLJIT_INLINE sljit_si emit_sse2_store(struct sljit_compiler *compiler, + sljit_si single, sljit_si dst, sljit_sw dstw, sljit_si src) { - return emit_sse2(compiler, 0x11, src, dst, dstw); + return emit_sse2(compiler, MOVSD_xm_x, single, src, dst, dstw); } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { - int dst_r; + sljit_si dst_r; CHECK_ERROR(); check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw); @@ -2127,57 +2327,57 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, in compiler->mode32 = 1; #endif - if (GET_OPCODE(op) == SLJIT_FCMP) { + if (GET_OPCODE(op) == SLJIT_CMPD) { compiler->flags_saved = 0; - if (dst >= SLJIT_FLOAT_REG1 && dst <= SLJIT_FLOAT_REG4) + if (dst <= SLJIT_FLOAT_REG6) dst_r = dst; else { dst_r = TMP_FREG; - FAIL_IF(emit_sse2_load(compiler, dst_r, dst, dstw)); + FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, dst_r, dst, dstw)); } - return emit_sse2_logic(compiler, 0x2e, dst_r, src, srcw); + return emit_sse2_logic(compiler, UCOMISD_x_xm, !(op & SLJIT_SINGLE_OP), dst_r, src, srcw); } - if (op == SLJIT_FMOV) { - if (dst >= SLJIT_FLOAT_REG1 && dst <= SLJIT_FLOAT_REG4) - return emit_sse2_load(compiler, dst, src, srcw); - if (src >= SLJIT_FLOAT_REG1 && src <= SLJIT_FLOAT_REG4) - return emit_sse2_store(compiler, dst, dstw, src); - FAIL_IF(emit_sse2_load(compiler, TMP_FREG, src, srcw)); - return emit_sse2_store(compiler, dst, dstw, TMP_FREG); + if (op == SLJIT_MOVD) { + if (dst <= SLJIT_FLOAT_REG6) + return emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, dst, src, srcw); + if (src <= SLJIT_FLOAT_REG6) + return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, src); + FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, TMP_FREG, src, srcw)); + return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, TMP_FREG); } - if (dst >= SLJIT_FLOAT_REG1 && dst <= SLJIT_FLOAT_REG4) { + if (dst >= SLJIT_FLOAT_REG1 && dst <= SLJIT_FLOAT_REG6) { dst_r = dst; if (dst != src) - FAIL_IF(emit_sse2_load(compiler, dst_r, src, srcw)); + FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, dst_r, src, srcw)); } else { dst_r = TMP_FREG; - FAIL_IF(emit_sse2_load(compiler, dst_r, src, srcw)); + FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, dst_r, src, srcw)); } - switch (op) { - case SLJIT_FNEG: - FAIL_IF(emit_sse2_logic(compiler, 0x57, dst_r, SLJIT_MEM0(), (sljit_w)sse2_buffer)); + switch (GET_OPCODE(op)) { + case SLJIT_NEGD: + FAIL_IF(emit_sse2_logic(compiler, XORPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_SINGLE_OP ? sse2_buffer : sse2_buffer + 8))); break; - case SLJIT_FABS: - FAIL_IF(emit_sse2_logic(compiler, 0x54, dst_r, SLJIT_MEM0(), (sljit_w)(sse2_buffer + 4))); + case SLJIT_ABSD: + FAIL_IF(emit_sse2_logic(compiler, ANDPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_SINGLE_OP ? sse2_buffer + 4 : sse2_buffer + 12))); break; } if (dst_r == TMP_FREG) - return emit_sse2_store(compiler, dst, dstw, TMP_FREG); + return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, TMP_FREG); return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(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) { - int dst_r; + sljit_si dst_r; CHECK_ERROR(); check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w); @@ -2186,55 +2386,55 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, in compiler->mode32 = 1; #endif - if (dst >= SLJIT_FLOAT_REG1 && dst <= SLJIT_FLOAT_REG4) { + if (dst <= SLJIT_FLOAT_REG6) { dst_r = dst; if (dst == src1) ; /* Do nothing here. */ - else if (dst == src2 && (op == SLJIT_FADD || op == SLJIT_FMUL)) { + else if (dst == src2 && (op == SLJIT_ADDD || op == SLJIT_MULD)) { /* Swap arguments. */ src2 = src1; src2w = src1w; } else if (dst != src2) - FAIL_IF(emit_sse2_load(compiler, dst_r, src1, src1w)); + FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, dst_r, src1, src1w)); else { dst_r = TMP_FREG; - FAIL_IF(emit_sse2_load(compiler, TMP_FREG, src1, src1w)); + FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, TMP_FREG, src1, src1w)); } } else { dst_r = TMP_FREG; - FAIL_IF(emit_sse2_load(compiler, TMP_FREG, src1, src1w)); + FAIL_IF(emit_sse2_load(compiler, op & SLJIT_SINGLE_OP, TMP_FREG, src1, src1w)); } - switch (op) { - case SLJIT_FADD: - FAIL_IF(emit_sse2(compiler, 0x58, dst_r, src2, src2w)); + switch (GET_OPCODE(op)) { + case SLJIT_ADDD: + FAIL_IF(emit_sse2(compiler, ADDSD_x_xm, op & SLJIT_SINGLE_OP, dst_r, src2, src2w)); break; - case SLJIT_FSUB: - FAIL_IF(emit_sse2(compiler, 0x5c, dst_r, src2, src2w)); + case SLJIT_SUBD: + FAIL_IF(emit_sse2(compiler, SUBSD_x_xm, op & SLJIT_SINGLE_OP, dst_r, src2, src2w)); break; - case SLJIT_FMUL: - FAIL_IF(emit_sse2(compiler, 0x59, dst_r, src2, src2w)); + case SLJIT_MULD: + FAIL_IF(emit_sse2(compiler, MULSD_x_xm, op & SLJIT_SINGLE_OP, dst_r, src2, src2w)); break; - case SLJIT_FDIV: - FAIL_IF(emit_sse2(compiler, 0x5e, dst_r, src2, src2w)); + case SLJIT_DIVD: + FAIL_IF(emit_sse2(compiler, DIVSD_x_xm, op & SLJIT_SINGLE_OP, dst_r, src2, src2w)); break; } if (dst_r == TMP_FREG) - return emit_sse2_store(compiler, dst, dstw, TMP_FREG); + return emit_sse2_store(compiler, op & SLJIT_SINGLE_OP, dst, dstw, TMP_FREG); return SLJIT_SUCCESS; } #else -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop1(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw) { CHECK_ERROR(); /* Should cause an assertion fail. */ @@ -2243,10 +2443,10 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop1(struct sljit_compiler *compiler, in return SLJIT_ERR_UNSUPPORTED; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, int op, - int dst, sljit_w dstw, - int src1, sljit_w src1w, - int src2, sljit_w src2w) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fop2(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(); /* Should cause an assertion fail. */ @@ -2263,7 +2463,7 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_fop2(struct sljit_compiler *compiler, in SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler) { - sljit_ub *buf; + sljit_ub *inst; struct sljit_label *label; CHECK_ERROR_PTR(); @@ -2281,18 +2481,18 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi PTR_FAIL_IF(!label); set_label(label, compiler); - buf = (sljit_ub*)ensure_buf(compiler, 2); - PTR_FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 2); + PTR_FAIL_IF(!inst); - *buf++ = 0; - *buf++ = 0; + *inst++ = 0; + *inst++ = 0; return label; } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, int type) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_si type) { - sljit_ub *buf; + sljit_ub *inst; struct sljit_jump *jump; CHECK_ERROR_PTR(); @@ -2319,17 +2519,17 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile compiler->size += (type >= SLJIT_JUMP) ? (10 + 3) : (2 + 10 + 3); #endif - buf = (sljit_ub*)ensure_buf(compiler, 2); - PTR_FAIL_IF_NULL(buf); + inst = (sljit_ub*)ensure_buf(compiler, 2); + PTR_FAIL_IF_NULL(inst); - *buf++ = 0; - *buf++ = type + 4; + *inst++ = 0; + *inst++ = type + 4; return jump; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, int type, int src, sljit_w srcw) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compiler, sljit_si type, sljit_si src, sljit_sw srcw) { - sljit_ub *code; + sljit_ub *inst; struct sljit_jump *jump; CHECK_ERROR(); @@ -2347,19 +2547,16 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i if (type >= SLJIT_CALL1) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) #if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) - if (src == SLJIT_TEMPORARY_REG3) { + if (src == SLJIT_SCRATCH_REG3) { EMIT_MOV(compiler, TMP_REGISTER, 0, src, 0); src = TMP_REGISTER; } if (src == SLJIT_MEM1(SLJIT_LOCALS_REG) && type >= SLJIT_CALL3) - srcw += sizeof(sljit_w); -#else - if (src == SLJIT_MEM1(SLJIT_LOCALS_REG)) - srcw += sizeof(sljit_w) * (type - SLJIT_CALL0); + srcw += sizeof(sljit_sw); #endif #endif #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && defined(_WIN64) - if (src == SLJIT_TEMPORARY_REG3) { + if (src == SLJIT_SCRATCH_REG3) { EMIT_MOV(compiler, TMP_REGISTER, 0, src, 0); src = TMP_REGISTER; } @@ -2380,37 +2577,42 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_ijump(struct sljit_compiler *compiler, i compiler->size += 10 + 3; #endif - code = (sljit_ub*)ensure_buf(compiler, 2); - FAIL_IF_NULL(code); + inst = (sljit_ub*)ensure_buf(compiler, 2); + FAIL_IF_NULL(inst); - *code++ = 0; - *code++ = type + 4; + *inst++ = 0; + *inst++ = type + 4; } else { #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) /* REX_W is not necessary (src is not immediate). */ compiler->mode32 = 1; #endif - code = emit_x86_instruction(compiler, 1, 0, 0, src, srcw); - FAIL_IF(!code); - *code++ = 0xff; - *code |= (type >= SLJIT_FAST_CALL) ? (2 << 3) : (4 << 3); + inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw); + FAIL_IF(!inst); + *inst++ = GROUP_FF; + *inst |= (type >= SLJIT_FAST_CALL) ? CALL_rm : JMP_rm; } return SLJIT_SUCCESS; } -SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compiler, int op, int dst, sljit_w dstw, int type) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_si op, + sljit_si dst, sljit_sw dstw, + sljit_si src, sljit_sw srcw, + sljit_si type) { - sljit_ub *buf; + sljit_ub *inst; sljit_ub cond_set = 0; - int dst_save = dst; - sljit_w dstw_save = dstw; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - int reg; + sljit_si reg; +#else + /* CHECK_EXTRA_REGS migh overwrite these values. */ + sljit_si dst_save = dst; + sljit_sw dstw_save = dstw; #endif CHECK_ERROR(); - check_sljit_emit_cond_value(compiler, op, dst, dstw, type); + check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type); if (dst == SLJIT_UNUSED) return SLJIT_SUCCESS; @@ -2420,177 +2622,165 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(struct sljit_compiler *compil if (SLJIT_UNLIKELY(compiler->flags_saved)) FAIL_IF(emit_restore_flags(compiler, op & SLJIT_KEEP_FLAGS)); - switch (type) { - case SLJIT_C_EQUAL: - case SLJIT_C_FLOAT_EQUAL: - cond_set = 0x94; - break; - - case SLJIT_C_NOT_EQUAL: - case SLJIT_C_FLOAT_NOT_EQUAL: - cond_set = 0x95; - break; - - case SLJIT_C_LESS: - case SLJIT_C_FLOAT_LESS: - cond_set = 0x92; - break; - - case SLJIT_C_GREATER_EQUAL: - case SLJIT_C_FLOAT_GREATER_EQUAL: - cond_set = 0x93; - break; - - case SLJIT_C_GREATER: - case SLJIT_C_FLOAT_GREATER: - cond_set = 0x97; - break; - - case SLJIT_C_LESS_EQUAL: - case SLJIT_C_FLOAT_LESS_EQUAL: - cond_set = 0x96; - break; - - case SLJIT_C_SIG_LESS: - cond_set = 0x9c; - break; - - case SLJIT_C_SIG_GREATER_EQUAL: - cond_set = 0x9d; - break; - - case SLJIT_C_SIG_GREATER: - cond_set = 0x9f; - break; - - case SLJIT_C_SIG_LESS_EQUAL: - cond_set = 0x9e; - break; - - case SLJIT_C_OVERFLOW: - case SLJIT_C_MUL_OVERFLOW: - cond_set = 0x90; - break; - - case SLJIT_C_NOT_OVERFLOW: - case SLJIT_C_MUL_NOT_OVERFLOW: - cond_set = 0x91; - break; - - case SLJIT_C_FLOAT_NAN: - cond_set = 0x9a; - break; - - case SLJIT_C_FLOAT_NOT_NAN: - cond_set = 0x9b; - break; - } + /* setcc = jcc + 0x10. */ + cond_set = get_jump_code(type) + 0x10; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - reg = (op == SLJIT_MOV && dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REGISTER; + if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && dst <= TMP_REGISTER && dst == src) { + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 + 3); + FAIL_IF(!inst); + INC_SIZE(4 + 3); + /* Set low register to conditional flag. */ + *inst++ = (reg_map[TMP_REGISTER] <= 7) ? REX : REX_B; + *inst++ = GROUP_0F; + *inst++ = cond_set; + *inst++ = MOD_REG | reg_lmap[TMP_REGISTER]; + *inst++ = REX | (reg_map[TMP_REGISTER] <= 7 ? 0 : REX_R) | (reg_map[dst] <= 7 ? 0 : REX_B); + *inst++ = OR_rm8_r8; + *inst++ = MOD_REG | (reg_lmap[TMP_REGISTER] << 3) | reg_lmap[dst]; + return SLJIT_SUCCESS; + } - buf = (sljit_ub*)ensure_buf(compiler, 1 + 4 + 4); - FAIL_IF(!buf); + reg = (op == SLJIT_MOV && dst <= TMP_REGISTER) ? dst : TMP_REGISTER; + + inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 + 4); + FAIL_IF(!inst); INC_SIZE(4 + 4); /* Set low register to conditional flag. */ - *buf++ = (reg_map[reg] <= 7) ? 0x40 : REX_B; - *buf++ = 0x0f; - *buf++ = cond_set; - *buf++ = 0xC0 | reg_lmap[reg]; - *buf++ = REX_W | (reg_map[reg] <= 7 ? 0 : (REX_B | REX_R)); - *buf++ = 0x0f; - *buf++ = 0xb6; - *buf = 0xC0 | (reg_lmap[reg] << 3) | reg_lmap[reg]; + *inst++ = (reg_map[reg] <= 7) ? REX : REX_B; + *inst++ = GROUP_0F; + *inst++ = cond_set; + *inst++ = MOD_REG | reg_lmap[reg]; + *inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : (REX_B | REX_R)); + *inst++ = GROUP_0F; + *inst++ = MOVZX_r_rm8; + *inst = MOD_REG | (reg_lmap[reg] << 3) | reg_lmap[reg]; - if (reg == TMP_REGISTER) { - if (op == SLJIT_MOV) { - compiler->mode32 = 0; - EMIT_MOV(compiler, dst, dstw, TMP_REGISTER, 0); - } - else { -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) - compiler->skip_checks = 1; -#endif - return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REGISTER, 0); - } + if (reg != TMP_REGISTER) + return SLJIT_SUCCESS; + + if (GET_OPCODE(op) < SLJIT_ADD) { + compiler->mode32 = GET_OPCODE(op) != SLJIT_MOV; + return emit_mov(compiler, dst, dstw, TMP_REGISTER, 0); } -#else - if (op == SLJIT_MOV) { - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_TEMPORARY_REG3) { - buf = (sljit_ub*)ensure_buf(compiler, 1 + 3 + 3); - FAIL_IF(!buf); +#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) + compiler->skip_checks = 1; +#endif + return sljit_emit_op2(compiler, op, dst, dstw, dst, dstw, TMP_REGISTER, 0); +#else /* SLJIT_CONFIG_X86_64 */ + if (GET_OPCODE(op) < SLJIT_ADD && dst <= TMP_REGISTER) { + if (reg_map[dst] <= 4) { + /* Low byte is accessible. */ + inst = (sljit_ub*)ensure_buf(compiler, 1 + 3 + 3); + FAIL_IF(!inst); INC_SIZE(3 + 3); /* Set low byte to conditional flag. */ - *buf++ = 0x0f; - *buf++ = cond_set; - *buf++ = 0xC0 | reg_map[dst]; + *inst++ = GROUP_0F; + *inst++ = cond_set; + *inst++ = MOD_REG | reg_map[dst]; - *buf++ = 0x0f; - *buf++ = 0xb6; - *buf = 0xC0 | (reg_map[dst] << 3) | reg_map[dst]; + *inst++ = GROUP_0F; + *inst++ = MOVZX_r_rm8; + *inst = MOD_REG | (reg_map[dst] << 3) | reg_map[dst]; + return SLJIT_SUCCESS; } - else { - EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_TEMPORARY_REG1, 0); - buf = (sljit_ub*)ensure_buf(compiler, 1 + 3 + 3); - FAIL_IF(!buf); - INC_SIZE(3 + 3); - /* Set al to conditional flag. */ - *buf++ = 0x0f; - *buf++ = cond_set; - *buf++ = 0xC0; + /* Low byte is not accessible. */ + if (cpu_has_cmov == -1) + get_cpu_features(); - *buf++ = 0x0f; - *buf++ = 0xb6; - if (dst >= SLJIT_SAVED_REG1 && dst <= SLJIT_NO_REGISTERS) - *buf = 0xC0 | (reg_map[dst] << 3); - else { - *buf = 0xC0; - EMIT_MOV(compiler, dst, dstw, SLJIT_TEMPORARY_REG1, 0); - } + if (cpu_has_cmov) { + EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_IMM, 1); + /* a xor reg, reg operation would overwrite the flags. */ + EMIT_MOV(compiler, dst, 0, SLJIT_IMM, 0); - EMIT_MOV(compiler, SLJIT_TEMPORARY_REG1, 0, TMP_REGISTER, 0); - } - } - else { - if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_TEMPORARY_REG3) { - EMIT_MOV(compiler, TMP_REGISTER, 0, dst, 0); - buf = (sljit_ub*)ensure_buf(compiler, 1 + 3); - FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 1 + 3); + FAIL_IF(!inst); INC_SIZE(3); - *buf++ = 0x0f; - *buf++ = cond_set; - *buf++ = 0xC0 | reg_map[dst]; + *inst++ = GROUP_0F; + /* cmovcc = setcc - 0x50. */ + *inst++ = cond_set - 0x50; + *inst++ = MOD_REG | (reg_map[dst] << 3) | reg_map[TMP_REGISTER]; + return SLJIT_SUCCESS; + } + + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1); + FAIL_IF(!inst); + INC_SIZE(1 + 3 + 3 + 1); + *inst++ = XCHG_EAX_r + reg_map[TMP_REGISTER]; + /* Set al to conditional flag. */ + *inst++ = GROUP_0F; + *inst++ = cond_set; + *inst++ = MOD_REG | 0 /* eax */; + + *inst++ = GROUP_0F; + *inst++ = MOVZX_r_rm8; + *inst++ = MOD_REG | (reg_map[dst] << 3) | 0 /* eax */; + *inst++ = XCHG_EAX_r + reg_map[TMP_REGISTER]; + return SLJIT_SUCCESS; + } + + if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && dst <= TMP_REGISTER && dst == src && reg_map[dst] <= 4) { + SLJIT_COMPILE_ASSERT(reg_map[SLJIT_SCRATCH_REG1] == 0, scratch_reg1_must_be_eax); + if (dst != SLJIT_SCRATCH_REG1) { + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 3 + 2 + 1); + FAIL_IF(!inst); + INC_SIZE(1 + 3 + 2 + 1); + /* Set low register to conditional flag. */ + *inst++ = XCHG_EAX_r + reg_map[TMP_REGISTER]; + *inst++ = GROUP_0F; + *inst++ = cond_set; + *inst++ = MOD_REG | 0 /* eax */; + *inst++ = OR_rm8_r8; + *inst++ = MOD_REG | (0 /* eax */ << 3) | reg_map[dst]; + *inst++ = XCHG_EAX_r + reg_map[TMP_REGISTER]; } else { - EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_TEMPORARY_REG1, 0); - - buf = (sljit_ub*)ensure_buf(compiler, 1 + 3 + 3 + 1); - FAIL_IF(!buf); - INC_SIZE(3 + 3 + 1); - /* Set al to conditional flag. */ - *buf++ = 0x0f; - *buf++ = cond_set; - *buf++ = 0xC0; - - *buf++ = 0x0f; - *buf++ = 0xb6; - *buf++ = 0xC0; - - *buf++ = 0x90 + reg_map[TMP_REGISTER]; + inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + 3 + 2 + 2); + FAIL_IF(!inst); + INC_SIZE(2 + 3 + 2 + 2); + /* Set low register to conditional flag. */ + *inst++ = XCHG_r_rm; + *inst++ = MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REGISTER]; + *inst++ = GROUP_0F; + *inst++ = cond_set; + *inst++ = MOD_REG | 1 /* ecx */; + *inst++ = OR_rm8_r8; + *inst++ = MOD_REG | (1 /* ecx */ << 3) | 0 /* eax */; + *inst++ = XCHG_r_rm; + *inst++ = MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REGISTER]; } -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) - compiler->skip_checks = 1; -#endif - return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REGISTER, 0); + return SLJIT_SUCCESS; } -#endif - return SLJIT_SUCCESS; + /* Set TMP_REGISTER to the bit. */ + inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1); + FAIL_IF(!inst); + INC_SIZE(1 + 3 + 3 + 1); + *inst++ = XCHG_EAX_r + reg_map[TMP_REGISTER]; + /* Set al to conditional flag. */ + *inst++ = GROUP_0F; + *inst++ = cond_set; + *inst++ = MOD_REG | 0 /* eax */; + + *inst++ = GROUP_0F; + *inst++ = MOVZX_r_rm8; + *inst++ = MOD_REG | (0 << 3) /* eax */ | 0 /* eax */; + + *inst++ = XCHG_EAX_r + reg_map[TMP_REGISTER]; + + if (GET_OPCODE(op) < SLJIT_ADD) + return emit_mov(compiler, dst, dstw, TMP_REGISTER, 0); + +#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) || (defined SLJIT_DEBUG && SLJIT_DEBUG) + compiler->skip_checks = 1; +#endif + return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REGISTER, 0); +#endif /* SLJIT_CONFIG_X86_64 */ } -SLJIT_API_FUNC_ATTRIBUTE int sljit_get_local_base(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w offset) +SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset) { CHECK_ERROR(); check_sljit_get_local_base(compiler, dst, dstw, offset); @@ -2608,25 +2798,25 @@ SLJIT_API_FUNC_ATTRIBUTE int sljit_get_local_base(struct sljit_compiler *compile if (NOT_HALFWORD(offset)) { FAIL_IF(emit_load_imm64(compiler, TMP_REGISTER, offset)); #if (defined SLJIT_DEBUG && SLJIT_DEBUG) - SLJIT_ASSERT(emit_lea_binary(compiler, dst, dstw, SLJIT_LOCALS_REG, 0, TMP_REGISTER, 0) != SLJIT_ERR_UNSUPPORTED); + SLJIT_ASSERT(emit_lea_binary(compiler, SLJIT_KEEP_FLAGS, dst, dstw, SLJIT_LOCALS_REG, 0, TMP_REGISTER, 0) != SLJIT_ERR_UNSUPPORTED); return compiler->error; #else - return emit_lea_binary(compiler, dst, dstw, SLJIT_LOCALS_REG, 0, TMP_REGISTER, 0); + return emit_lea_binary(compiler, SLJIT_KEEP_FLAGS, dst, dstw, SLJIT_LOCALS_REG, 0, TMP_REGISTER, 0); #endif } #endif if (offset != 0) - return emit_lea_binary(compiler, dst, dstw, SLJIT_LOCALS_REG, 0, SLJIT_IMM, offset); + return emit_lea_binary(compiler, SLJIT_KEEP_FLAGS, dst, dstw, SLJIT_LOCALS_REG, 0, SLJIT_IMM, offset); return emit_mov(compiler, dst, dstw, SLJIT_LOCALS_REG, 0); } -SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, int dst, sljit_w dstw, sljit_w init_value) +SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value) { - sljit_ub *buf; + sljit_ub *inst; struct sljit_const *const_; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - int reg; + sljit_si reg; #endif CHECK_ERROR_PTR(); @@ -2641,7 +2831,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) compiler->mode32 = 0; - reg = (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) ? dst : TMP_REGISTER; + reg = (dst <= TMP_REGISTER) ? dst : TMP_REGISTER; if (emit_load_imm64(compiler, reg, init_value)) return NULL; @@ -2653,11 +2843,11 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi return NULL; #endif - buf = (sljit_ub*)ensure_buf(compiler, 2); - PTR_FAIL_IF(!buf); + inst = (sljit_ub*)ensure_buf(compiler, 2); + PTR_FAIL_IF(!inst); - *buf++ = 0; - *buf++ = 1; + *inst++ = 0; + *inst++ = 1; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if (reg == TMP_REGISTER && dst != SLJIT_UNUSED) @@ -2671,13 +2861,13 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr) { #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - *(sljit_w*)addr = new_addr - (addr + 4); + *(sljit_sw*)addr = new_addr - (addr + 4); #else *(sljit_uw*)addr = new_addr; #endif } -SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_w new_constant) +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant) { - *(sljit_w*)addr = new_constant; + *(sljit_sw*)addr = new_constant; } diff --git a/src/3rd/pcre/ucp.h b/src/3rd/pcre/ucp.h index 59c3bec3d3..d8b34bfcc5 100644 --- a/src/3rd/pcre/ucp.h +++ b/src/3rd/pcre/ucp.h @@ -7,7 +7,14 @@ /* This file contains definitions of the property values that are returned by the UCD access macros. New values that are added for new releases of Unicode -should always be at the end of each enum, for backwards compatibility. */ +should always be at the end of each enum, for backwards compatibility. + +IMPORTANT: Note also that the specific numeric values of the enums have to be +the same as the values that are generated by the maint/MultiStage2.py script, +where the equivalent property descriptive names are listed in vectors. + +ALSO: The specific values of the first two enums are assumed for the table +called catposstab in pcre_compile.c. */ /* These are the general character categories. */ @@ -21,7 +28,7 @@ enum { ucp_Z /* Separator */ }; -/* These are the particular character types. */ +/* These are the particular character categories. */ enum { ucp_Cc, /* Control */ @@ -56,6 +63,26 @@ enum { ucp_Zs /* Space separator */ }; +/* These are grapheme break properties. Note that the code for processing them +assumes that the values are less than 16. If more values are added that take +the number to 16 or more, the code will have to be rewritten. */ + +enum { + ucp_gbCR, /* 0 */ + ucp_gbLF, /* 1 */ + ucp_gbControl, /* 2 */ + ucp_gbExtend, /* 3 */ + ucp_gbPrepend, /* 4 */ + ucp_gbSpacingMark, /* 5 */ + ucp_gbL, /* 6 Hangul syllable type L */ + ucp_gbV, /* 7 Hangul syllable type V */ + ucp_gbT, /* 8 Hangul syllable type T */ + ucp_gbLV, /* 9 Hangul syllable type LV */ + ucp_gbLVT, /* 10 Hangul syllable type LVT */ + ucp_gbRegionalIndicator, /* 11 */ + ucp_gbOther /* 12 */ +}; + /* These are the script identifications. */ enum {